1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Interface to LibVEX_Translate, and the SP-update pass        ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                m_translate.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Copyright (C) 2000-2012 Julian Seward
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"    // VG_(fnptr_to_fnentry)
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 // VG_(get_SP)
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 // VG_(machine_get_VexArchInfo)
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_debuginfo.h"  // VG_(get_fnname_w_offset)
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_redir.h"      // VG_(redir_do_lookup)
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_signals.h"    // VG_(synth_fault_{perms,mapping}
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacks.h"     // VG_(unknown_SP_update)()
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"  // VG_(tdict)
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_translate.h"
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_transtab.h"
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_dispatch.h" // VG_(run_innerloop__dispatch_{un}profiled)
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               // VG_(run_a_noredir_translation__return_point)
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h"   // to keep _threadstate.h happy
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"  // VexGuestArchState
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_trampoline.h"   // VG_(ppctoc_magic_redirect_return_stub)
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_execontext.h"  // VG_(make_depth_1_ExeContext_from_Addr)
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_gdbserver.h"   // VG_(tool_instrument_then_gdbserver_if_needed)
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stats                                                ---*/
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_fast            = 0;
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_generic_known   = 0;
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_generic_unknown = 0;
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(print_translation_stats) ( void )
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Char buf[7];
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         + n_SP_updates_generic_unknown;
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate:            fast SP updates identified: %'u (%s)\n",
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_fast, buf );
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate:   generic_known SP updates identified: %'u (%s)\n",
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_generic_known, buf );
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate: generic_unknown SP updates identified: %'u (%s)\n",
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_generic_unknown, buf );
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- %SP-update pass                                      ---*/
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool need_to_handle_SP_assignment(void)
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( VG_(tdict).track_new_mem_stack_4   ||
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_4   ||
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_8   ||
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_8   ||
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_12  ||
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_12  ||
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_16  ||
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_16  ||
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_32  ||
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_32  ||
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_112 ||
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_112 ||
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_128 ||
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_128 ||
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_144 ||
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_144 ||
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_160 ||
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_160 ||
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack     ||
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack     );
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - The SP aliases are held in an array which is used as a circular buffer.
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   This misses very few constant updates of SP (ie. < 0.1%) while using a
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   small, constant structure that will also never fill up and cause
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   execution to abort.
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Unused slots have a .temp value of 'IRTemp_INVALID'.
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - 'next_SP_alias_slot' is the index where the next alias will be stored.
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - If the buffer fills, we circle around and start over-writing
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   non-IRTemp_INVALID values.  This is rare, and the overwriting of a
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   value that would have subsequently be used is even rarer.
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Every slot below next_SP_alias_slot holds a non-IRTemp_INVALID value.
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   The rest either all won't (if we haven't yet circled around) or all
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   will (if we have circled around).
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp temp;
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Long   delta;
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_Alias;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// With 32 slots the buffer fills very rarely -- eg. once in a run of GCC.
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// And I've tested with smaller values and the wrap-around case works ok.
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_ALIASES    32
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SP_Alias SP_aliases[N_ALIASES];
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int      next_SP_alias_slot = 0;
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void clear_SP_aliases(void)
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < N_ALIASES; i++) {
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].temp  = IRTemp_INVALID;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].delta = 0;
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_SP_alias_slot = 0;
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_SP_alias(IRTemp temp, Long delta)
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(temp != IRTemp_INVALID);
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_aliases[ next_SP_alias_slot ].temp  = temp;
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_aliases[ next_SP_alias_slot ].delta = delta;
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_SP_alias_slot++;
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (N_ALIASES == next_SP_alias_slot) next_SP_alias_slot = 0;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool get_SP_delta(IRTemp temp, ULong* delta)
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;      // i must be signed!
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(IRTemp_INVALID != temp);
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Search backwards between current buffer position and the start.
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = next_SP_alias_slot-1; i >= 0; i--) {
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (temp == SP_aliases[i].temp) {
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *delta = SP_aliases[i].delta;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Search backwards between the end and the current buffer position.
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = N_ALIASES-1; i >= next_SP_alias_slot; i--) {
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (temp == SP_aliases[i].temp) {
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *delta = SP_aliases[i].delta;
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_SP_aliases(Long delta)
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < N_ALIASES; i++) {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (SP_aliases[i].temp == IRTemp_INVALID) {
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].delta += delta;
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given a guest IP, get an origin tag for a 1-element stack trace,
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and wrap it up in an IR atom that can be passed as the origin-tag
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value for a stack-adjustment helper function. */
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_ecu_Expr ( Addr64 guest_IP )
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ecu;
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ExeContext* ec
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = VG_(make_depth_1_ExeContext_from_Addr)( (Addr)guest_IP );
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ec);
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ecu = VG_(get_ECU_from_ExeContext)( ec );
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_plausible_ECU)(ecu));
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is always safe to do, since ecu is only 32 bits, and
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HWord is 32 or 64. */
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkIRExpr_HWord( (HWord)ecu );
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* When gdbserver is activated, the translation of a block must
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   first be done by the tool function, then followed by a pass
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   which (if needed) instruments the code for gdbserver.
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovIRSB* tool_instrument_then_gdbserver_if_needed ( VgCallbackClosure* closureV,
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRSB*              sb_in,
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 VexGuestLayout*    layout,
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 VexGuestExtents*   vge,
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRType             gWordTy,
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRType             hWordTy )
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return VG_(instrument_for_gdbserver_if_needed)
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (VG_(tdict).tool_instrument (closureV,
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   sb_in,
229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   layout,
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   vge,
231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   gWordTy,
232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   hWordTy),
233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       layout,
234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       vge,
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       gWordTy,
236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       hWordTy);
237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For tools that want to know about SP changes, this pass adds
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in the appropriate hooks.  We have to do it after the tool's
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instrumentation, so the tool doesn't have to worry about the C calls
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it adds in, and we must do it before register allocation because
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spilled temps make it much harder to work out the SP deltas.
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This it is done with Vex's "second instrumentation" pass.
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Basically, we look for GET(SP)/PUT(SP) pairs and track constant
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   increments/decrements of SP between them.  (This requires tracking one or
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   more "aliases", which are not exact aliases but instead are tempregs
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whose value is equal to the SP's plus or minus a known constant.)
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If all the changes to SP leading up to a PUT(SP) are by known, small
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constants, we can do a specific call to eg. new_mem_stack_4, otherwise
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   we fall back to the case that handles an unknown SP change.
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There is some extra complexity to deal correctly with updates to
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only parts of SP.  Bizarre, but it has been known to happen.
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRSB* vg_SP_update_pass ( void*             closureV,
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRSB*             sb_in,
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VexGuestLayout*   layout,
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VexGuestExtents*  vge,
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRType            gWordTy,
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRType            hWordTy )
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
265663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int         i, j, k, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         first_SP, last_SP, first_Put, last_Put;
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty     *dcall, *d;
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt*     st;
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     e;
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType      typeof_SP;
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long        delta, con;
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up stuff for tracking the guest IP */
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   curr_IP_known = False;
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64 curr_IP       = 0;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up BB */
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB* bb     = emptyIRSB();
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->tyenv    = deepCopyIRTypeEnv(sb_in->tyenv);
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->next     = deepCopyIRExpr(sb_in->next);
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->jumpkind = sb_in->jumpkind;
283663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->offsIP   = sb_in->offsIP;
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta = 0;
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sizeof_SP = layout->sizeof_SP;
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   offset_SP = layout->offset_SP;
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64;
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof_SP == 4 || sizeof_SP == 8);
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- Start of #defines --- */
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64))
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64))
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op))
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define GET_CONST(con)                                                \
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32)                        \
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : (Long)(con->Ico.U64))
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO_NEW(syze, tmpp)                                            \
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do {                                                              \
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool vanilla, w_ecu;                                           \
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(curr_IP_known);                                      \
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vanilla = NULL != VG_(tdict).track_new_mem_stack_##syze;       \
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         w_ecu   = NULL != VG_(tdict).track_new_mem_stack_##syze##_w_ECU; \
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(!(vanilla && w_ecu)); /* can't have both */          \
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(vanilla || w_ecu))                                       \
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto generic;                                               \
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* I don't know if it's really necessary to say that the */    \
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* call reads the stack pointer.  But anyway, we do. */        \
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (w_ecu) {                                                   \
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(                                  \
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       2/*regparms*/,                                   \
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "track_new_mem_stack_" #syze "_w_ECU",           \
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)(                           \
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VG_(tdict).track_new_mem_stack_##syze##_w_ECU ), \
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_2(IRExpr_RdTmp(tmpp),                \
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mk_ecu_Expr(curr_IP))              \
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );                                                  \
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {                                                       \
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(                                  \
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       1/*regparms*/,                                   \
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "track_new_mem_stack_" #syze ,                   \
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)(                           \
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VG_(tdict).track_new_mem_stack_##syze ),      \
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_1(IRExpr_RdTmp(tmpp))                \
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );                                                  \
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }                                                              \
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->nFxState = 1;                                           \
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].fx     = Ifx_Read;                           \
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].offset = layout->offset_SP;                  \
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].size   = layout->sizeof_SP;                  \
337663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].nRepeats  = 0;                               \
338663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].repeatLen = 0;                               \
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( bb, IRStmt_Dirty(dcall) );                      \
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(syze > 0);                                           \
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_SP_aliases(syze);                                       \
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_fast++;                                           \
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } while (0)
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO_DIE(syze, tmpp)                                            \
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do {                                                              \
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!VG_(tdict).track_die_mem_stack_##syze)                    \
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto generic;                                               \
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* I don't know if it's really necessary to say that the */    \
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* call reads the stack pointer.  But anyway, we do. */        \
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall = unsafeIRDirty_0_N(                                     \
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    1/*regparms*/,                                      \
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "track_die_mem_stack_" #syze,                       \
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_(fnptr_to_fnentry)(                              \
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(tdict).track_die_mem_stack_##syze ),         \
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkIRExprVec_1(IRExpr_RdTmp(tmpp))                   \
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );                                                     \
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->nFxState = 1;                                           \
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].fx     = Ifx_Read;                           \
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].offset = layout->offset_SP;                  \
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].size   = layout->sizeof_SP;                  \
367663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].nRepeats  = 0;                               \
368663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].repeatLen = 0;                               \
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( bb, IRStmt_Dirty(dcall) );                      \
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(syze > 0);                                           \
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_SP_aliases(-(syze));                                    \
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_fast++;                                           \
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } while (0)
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- End of #defines --- */
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clear_SP_aliases();
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i <  sb_in->stmts_used; i++) {
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st = sb_in->stmts[i];
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_IMark) {
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_IP_known = True;
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_IP       = st->Ist.IMark.addr;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t = Get(sp):   curr = t, delta = 0 */
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case2;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_Get)              goto case2;
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Get.offset != offset_SP) goto case2;
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Get.ty != typeof_SP)     goto case2;
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_SP_alias(st->Ist.WrTmp.tmp, 0);
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case2:
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t' = curr +/- const:   curr = t',  delta +=/-= const */
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case3;
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_Binop) goto case3;
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Binop.arg1->tag != Iex_RdTmp) goto case3;
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto case3;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (IS_ADD(e->Iex.Binop.op)) {
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case3:
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t' = curr:   curr = t' */
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case4;
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_RdTmp) goto case4;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4;
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_SP_alias(st->Ist.WrTmp.tmp, delta);
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case4:
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Put(sp) = curr */
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* More generally, we must correctly handle a Put which writes
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any part of SP, not just the case where all of SP is
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         written. */
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_Put) goto case5;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      first_SP  = offset_SP;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      last_SP   = first_SP + sizeof_SP - 1;
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      first_Put = st->Ist.Put.offset;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      last_Put  = first_Put
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  + sizeofIRType( typeOfIRExpr( bb->tyenv, st->Ist.Put.data ))
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  - 1;
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(first_SP <= last_SP);
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(first_Put <= last_Put);
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (last_Put < first_SP || last_SP < first_Put)
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto case5; /* no overlap */
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->Ist.Put.data->tag == Iex_RdTmp
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) {
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp tttmp = st->Ist.Put.data->Iex.RdTmp.tmp;
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Why should the following assertion hold?  Because any
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            alias added by put_SP_alias must be of a temporary which
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            has the same type as typeof_SP, and whose value is a Get
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            at exactly offset_SP of size typeof_SP.  Each call to
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            put_SP_alias is immediately preceded by an assertion that
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we are putting in a binding for a correctly-typed
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            temporary. */
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert( typeOfIRTemp(bb->tyenv, tttmp) == typeof_SP );
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* From the same type-and-offset-correctness argument, if
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we found a useable alias, it must for an "exact" write of SP. */
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(first_SP == first_Put);
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(last_SP == last_Put);
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (delta) {
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    0:                      addStmtToIRSB(bb,st); continue;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    4: DO_DIE(  4,  tttmp); addStmtToIRSB(bb,st); continue;
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   -4: DO_NEW(  4,  tttmp); addStmtToIRSB(bb,st); continue;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    8: DO_DIE(  8,  tttmp); addStmtToIRSB(bb,st); continue;
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   -8: DO_NEW(  8,  tttmp); addStmtToIRSB(bb,st); continue;
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   12: DO_DIE(  12, tttmp); addStmtToIRSB(bb,st); continue;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -12: DO_NEW(  12, tttmp); addStmtToIRSB(bb,st); continue;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   16: DO_DIE(  16, tttmp); addStmtToIRSB(bb,st); continue;
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -16: DO_NEW(  16, tttmp); addStmtToIRSB(bb,st); continue;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   32: DO_DIE(  32, tttmp); addStmtToIRSB(bb,st); continue;
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -32: DO_NEW(  32, tttmp); addStmtToIRSB(bb,st); continue;
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  112: DO_DIE( 112, tttmp); addStmtToIRSB(bb,st); continue;
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -112: DO_NEW( 112, tttmp); addStmtToIRSB(bb,st); continue;
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  128: DO_DIE( 128, tttmp); addStmtToIRSB(bb,st); continue;
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -128: DO_NEW( 128, tttmp); addStmtToIRSB(bb,st); continue;
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  144: DO_DIE( 144, tttmp); addStmtToIRSB(bb,st); continue;
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -144: DO_NEW( 144, tttmp); addStmtToIRSB(bb,st); continue;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  160: DO_DIE( 160, tttmp); addStmtToIRSB(bb,st); continue;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -160: DO_NEW( 160, tttmp); addStmtToIRSB(bb,st); continue;
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* common values for ppc64: 144 128 160 112 176 */
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               n_SP_updates_generic_known++;
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto generic;
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Deal with an unknown update to SP.  We're here because
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            either:
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (1) the Put does not exactly cover SP; it is a partial update.
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Highly unlikely, but has been known to happen for 16-bit
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Windows apps running on Wine, doing 16-bit adjustments to
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                %sp.
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (2) the Put does exactly cover SP, but we are unable to
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                determine how the value relates to the old SP.  In any
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                case, we cannot assume that the Put.data value is a tmp;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                we must assume it can be anything allowed in flat IR (tmp
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                or const).
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  old_SP;
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_generic_unknown++;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: if all is well, this generic case will typically be
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // called something like every 1000th SP update.  If it's more than
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // that, the above code may be missing some cases.
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        generic:
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Pass both the old and new SP values to this helper.  Also,
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pass an origin tag, even if it isn't needed. */
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old_SP = newIRTemp(bb->tyenv, typeof_SP);
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB(
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bb,
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now we know what the old value of SP is.  But knowing the new
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            value is a bit tricky if there is a partial write. */
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (first_Put == first_SP && last_Put == last_SP) {
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* The common case, an exact write to SP.  So st->Ist.Put.data
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              does hold the new value; simple. */
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(curr_IP_known);
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       3/*regparms*/,
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "VG_(unknown_SP_update)",
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_3( IRExpr_RdTmp(old_SP), st->Ist.Put.data,
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mk_ecu_Expr(curr_IP) )
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* don't forget the original assignment */
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, st );
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We have a partial update to SP.  We need to know what
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the new SP will be, and hand that to the helper call,
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               but when the helper call happens, SP must hold the
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               value it had before the update.  Tricky.
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Therefore use the following kludge:
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               1. do the partial SP update (Put)
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               2. Get the new SP value into a tmp, new_SP
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               3. Put old_SP
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               4. Call the helper
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               5. Put new_SP
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            */
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp new_SP;
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 1 */
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, st );
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 2 */
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            new_SP = newIRTemp(bb->tyenv, typeof_SP);
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB(
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               bb,
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRStmt_WrTmp( new_SP, IRExpr_Get(offset_SP, typeof_SP) )
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 3 */
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(old_SP) ));
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 4 */
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(curr_IP_known);
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       3/*regparms*/,
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "VG_(unknown_SP_update)",
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_3( IRExpr_RdTmp(old_SP),
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_RdTmp(new_SP),
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mk_ecu_Expr(curr_IP) )
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 5 */
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(new_SP) ));
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Forget what we already know. */
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         clear_SP_aliases();
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If this is a Put of a tmp that exactly updates SP,
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            start tracking aliases against this tmp. */
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (first_Put == first_SP && last_Put == last_SP
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && st->Ist.Put.data->tag == Iex_RdTmp) {
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.Put.data->Iex.RdTmp.tmp)
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       == typeof_SP );
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case5:
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PutI or Dirty call which overlaps SP: complain.  We can't
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         deal with SP changing in weird ways (well, we can, but not at
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this time of night).  */
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_PutI) {
593663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         descr = st->Ist.PutI.details->descr;
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         minoff_ST = descr->base;
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maxoff_ST = descr->base
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     + descr->nElems * sizeofIRType(descr->elemTy) - 1;
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(offset_SP > maxoff_ST
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               || (offset_SP + sizeof_SP - 1) < minoff_ST))
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto complain;
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_Dirty) {
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d = st->Ist.Dirty.details;
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (j = 0; j < d->nFxState; j++) {
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (d->fxState[j].fx == Ifx_Read || d->fxState[j].fx == Ifx_None)
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue;
606663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            /* Enumerate the described state segments */
607663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            for (k = 0; k < 1 + d->fxState[j].nRepeats; k++) {
608663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               minoff_ST = d->fxState[j].offset + k * d->fxState[j].repeatLen;
609663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               maxoff_ST = minoff_ST + d->fxState[j].size - 1;
610663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               if (!(offset_SP > maxoff_ST
611663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     || (offset_SP + sizeof_SP - 1) < minoff_ST))
612663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  goto complain;
613663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            }
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* well, not interesting.  Just copy and keep going. */
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* for (i = 0; i < sb_in->stmts_used; i++) */
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return bb;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  complain:
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP");
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_ADD
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_SUB
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_ADD_OR_SUB
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef GET_CONST
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DO_NEW
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DO_DIE
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Main entry point for the JITter.                     ---*/
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extra comments re self-checking translations and self-modifying
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   code.  (JRS 14 Oct 05).
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are 3 modes:
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (1) no checking: all code assumed to be not self-modifying
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (2) partial: known-problematic situations get a self-check
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (3) full checking: all translations get a self-check
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   As currently implemented, the default is (2).  (3) is always safe,
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but very slow.  (1) works mostly, but fails for gcc nested-function
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   code which uses trampolines on the stack; this situation is
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   detected and handled by (2).
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A more robust and transparent solution, which is not currently
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implemented, is a variant of (2): if a translation is made from an
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   area which aspacem says does not have 'w' permission, then it can
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be non-self-checking.  Otherwise, it needs a self-check.
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This is complicated by Vex's basic-block chasing.  If a self-check
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is requested, then Vex will not chase over basic block boundaries
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (it's too complex).  However there is still a problem if it chases
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from a non-'w' area into a 'w' area.
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I think the right thing to do is:
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - if a translation request starts in a 'w' area, ask for a
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     self-checking translation, and do not allow any chasing (make
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     chase_into_ok return False).  Note that the latter is redundant
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     in the sense that Vex won't chase anyway in this situation.
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - if a translation request starts in a non-'w' area, do not ask for
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     a self-checking translation.  However, do not allow chasing (as
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     determined by chase_into_ok) to go into a 'w' area.
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The result of this is that all code inside 'w' areas is self
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   checking.
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   To complete the trick, there is a caveat: we must watch the
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   client's mprotect calls.  If pages are changed from non-'w' to 'w'
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   then we should throw away all translations which intersect the
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   affected area, so as to force them to be redone with self-checks.
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The above outlines the conditions under which bb chasing is allowed
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from a self-modifying-code point of view.  There are other
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   situations pertaining to function redirection in which it is
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   necessary to disallow chasing, but those fall outside the scope of
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this comment.
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vex dumps the final code in here.  Then we can copy it off
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wherever we like. */
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 60000: should agree with assertion in VG_(add_to_transtab) in
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   m_transtab.c. */
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_TMPBUF 60000
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar tmpbuf[N_TMPBUF];
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Function pointers we must supply to LibVEX in order that it
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can bomb out and emit messages under Valgrind's control. */
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__ ((noreturn))
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid failure_exit ( void )
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_ShowAllocStats();
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(core_panic)("LibVEX called failure_exit().");
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid log_bytes ( HChar* bytes, Int nbytes )
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Int i;
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (i = 0; i < nbytes-3; i += 4)
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(printf)("%c%c%c%c", bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (; i < nbytes; i++)
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(printf)("%c", bytes[i]);
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Various helper functions for translation --------- */
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Look for reasons to disallow making translations from the given
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   segment. */
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool translations_allowable_from_seg ( NSegment const* seg )
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
729663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGA_x86) || defined(VGA_s390x) || defined(VGA_mips32)
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool allowR = True;
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool allowR = False;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return seg != NULL
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (seg->kind == SkAnonC || seg->kind == SkFileC || seg->kind == SkShmC)
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (seg->hasX || (seg->hasR && allowR));
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
740b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Produce a bitmask stating which of the supplied extents needs a
741b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   self-check.  See documentation of
742b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexTranslateArgs::needs_self_check for more details about the
743b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return convention. */
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic UInt needs_self_check ( void* closureV,
746b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                               VexGuestExtents* vge )
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
748b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
749b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt i, bitset;
750b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
751b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
752b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   bitset = 0;
753b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
754b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < vge->n_used; i++) {
755b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool  check = False;
756b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Addr  addr  = (Addr)vge->base[i];
757b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SizeT len   = (SizeT)vge->len[i];
758b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      NSegment const* segA = NULL;
759b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
760b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#     if defined(VGO_darwin)
761b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // GrP fixme hack - dyld i386 IMPORT gets rewritten.
762b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // To really do this correctly, we'd need to flush the
763b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // translation cache whenever a segment became +WX.
764b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      segA = VG_(am_find_nsegment)(addr);
765b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (segA && segA->hasX && segA->hasW)
766b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         check = True;
767b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#     endif
768b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
769b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!check) {
770b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         switch (VG_(clo_smc_check)) {
771b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcNone:
772b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* never check (except as per Darwin hack above) */
773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcAll:
775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* always check */
776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               check = True;
777b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
778b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcStack: {
779b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* check if the address is in the same segment as this
780b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  thread's stack pointer */
781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               Addr sp = VG_(get_SP)(closure->tid);
782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (!segA) {
783b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  segA = VG_(am_find_nsegment)(addr);
784b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
785b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               NSegment const* segSP = VG_(am_find_nsegment)(sp);
786b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (segA && segSP && segA == segSP)
787b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  check = True;
788b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
789b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
790b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcAllNonFile: {
791b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* check if any part of the extent is not in a
792b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  file-mapped segment */
793b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (!segA) {
794b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  segA = VG_(am_find_nsegment)(addr);
795b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
796b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (segA && segA->kind == SkFileC && segA->start <= addr
797b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   && (len == 0 || addr + len <= segA->end + 1)) {
798b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  /* in a file-mapped segment; skip the check */
799b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               } else {
800b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  check = True;
801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            default:
805b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               vg_assert(0);
806b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
807b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
808b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
809b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (check)
810b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         bitset |= (1 << i);
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
812b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
813b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return bitset;
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is a callback passed to LibVEX_Translate.  It stops Vex from
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   chasing into function entry points that we wish to redirect.
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Chasing across them obviously defeats the redirect mechanism, with
820b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   bad effects for Memcheck, Helgrind, DRD, Massif, and possibly others.
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool chase_into_ok ( void* closureV, Addr64 addr64 )
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr               addr    = (Addr)addr64;
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const*    seg     = VG_(am_find_nsegment)(addr);
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Work through a list of possibilities why we might not want to
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allow a chase. */
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Destination not in a plausible segment? */
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!translations_allowable_from_seg(seg))
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Destination is redirected? */
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addr != VG_(redir_do_lookup)(addr, NULL))
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This needs to be at the start of its own block.  Don't chase. Re
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong_to_Ptr, be careful to ensure we only compare 32 bits on a
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      32-bit target.*/
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ULong_to_Ptr(addr64)
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       == (void*)&VG_(ppctoc_magic_redirect_return_stub))
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* overly conservative, but .. don't chase into the distinguished
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      address that m_transtab uses as an empty-slot marker for
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tt_fast). */
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addr == TRANSTAB_BOGUS_GUEST_ADDR)
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
853b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGA_s390x)
854b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Never chase into an EX instruction. Generating IR for EX causes
855b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      a round-trip through the scheduler including VG_(discard_translations).
856b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      And that's expensive as shown by perf/tinycc.c:
857b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Chasing into EX increases the number of EX translations from 21 to
858b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      102666 causing a 7x runtime increase for "none" and a 3.2x runtime
859b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      increase for memcheck. */
860b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (((UChar *)ULong_to_Ptr(addr))[0] == 0x44 ||   /* EX */
861b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       ((UChar *)ULong_to_Ptr(addr))[0] == 0xC6)     /* EXRL */
862b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     goto dontchase;
863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* well, ok then.  go on and chase. */
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  dontchase:
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("not chasing into 0x%lx\n", addr);
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- helpers for with-TOC platforms --------------- */
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
879b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* NOTE: with-TOC platforms are: ppc64-linux. */
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong n ) {
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(n));
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( UInt n ) {
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32(n));
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VG_PLAT_USES_PPCTOC)
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( UChar n ) {
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8(n));
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* narrowTo32 ( IRTypeEnv* tyenv, IRExpr* e ) {
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (typeOfIRExpr(tyenv, e) == Ity_I32) {
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(typeOfIRExpr(tyenv, e) == Ity_I64);
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return IRExpr_Unop(Iop_64to32, e);
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to push word-typed expression 'e' onto this thread's
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redir stack, checking for stack overflow and generating code to
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bomb out if so. */
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_PUSH ( IRSB* bb, IRExpr* e )
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      t1;
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     one;
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC64State,guest_REDIR_SP);
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_EMWARN      = offsetof(VexGuestPPC64State,guest_EMWARN);
916663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC64State,guest_CIA);
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = True;
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I64;
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE64;
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar64;
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub64;
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Add           = Iop_Add64;
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(ULong)    = mkU64;
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_WORDSIZE == 8);
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC32State,guest_REDIR_SP);
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_EMWARN      = offsetof(VexGuestPPC32State,guest_EMWARN);
930663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC32State,guest_CIA);
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = False;
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I32;
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE32;
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar32;
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub32;
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Add           = Iop_Add32;
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(UInt)     = mkU32;
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_WORDSIZE == 4);
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(void*) == VG_WORDSIZE);
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Word)  == VG_WORDSIZE);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Addr)  == VG_WORDSIZE);
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t1    = newIRTemp( bb->tyenv, ty_Word );
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   one   = mkU(1);
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(typeOfIRExpr(bb->tyenv, e) == ty_Word);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 = guest_REDIR_SP + 1 */
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp(
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1,
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(op_Add, IRExpr_Get( offB_REDIR_SP, ty_Word ), one)
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bomb out if t1 >=s stack_size, that is, (stack_size-1)-t1 <s 0.
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The destination (0) is a bit bogus but it doesn't matter since
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this is an unrecoverable error and will lead to Valgrind
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      shutting down.  _EMWARN is set regardless - that's harmless
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since is only has a meaning if the exit is taken. */
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(offB_EMWARN, mkU32(EmWarn_PPC64_redir_overflow))
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op_CmpNE,
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Binop(
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op_Sar,
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Binop(op_Sub,mkU(stack_size-1),IRExpr_RdTmp(t1)),
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(8 * VG_WORDSIZE - 1)
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU(0)
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_EmFail,
982663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         is64 ? IRConst_U64(0) : IRConst_U32(0),
983663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         offB_CIA
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_SP = t1 */
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(bb, IRStmt_Put(offB_REDIR_SP, IRExpr_RdTmp(t1)));
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_STACK[t1+0] = e */
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* PutI/GetI have I32-typed indexes regardless of guest word size */
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
994663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      IRStmt_PutI(mkIRPutI(descr,
995663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                           narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0, e)));
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to pop a word-sized value from this thread's redir
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack, binding it to a new temporary, which is returned.  As with
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH, an overflow check is also performed. */
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_POP ( IRSB* bb )
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1005b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC64State,guest_REDIR_SP);
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_EMWARN      = offsetof(VexGuestPPC64State,guest_EMWARN);
1010663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC64State,guest_CIA);
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = True;
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I64;
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE64;
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar64;
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub64;
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(ULong)    = mkU64;
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC32State,guest_REDIR_SP);
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_EMWARN      = offsetof(VexGuestPPC32State,guest_EMWARN);
1022663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC32State,guest_CIA);
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = False;
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I32;
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE32;
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar32;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub32;
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(UInt)     = mkU32;
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      t1    = newIRTemp( bb->tyenv, ty_Word );
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      res   = newIRTemp( bb->tyenv, ty_Word );
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     one   = mkU(1);
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(void*) == VG_WORDSIZE);
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Word)  == VG_WORDSIZE);
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Addr)  == VG_WORDSIZE);
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 = guest_REDIR_SP */
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp( t1, IRExpr_Get( offB_REDIR_SP, ty_Word ) )
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bomb out if t1 < 0.  Same comments as gen_PUSH apply. */
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(offB_EMWARN, mkU32(EmWarn_PPC64_redir_underflow))
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op_CmpNE,
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Binop(
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op_Sar,
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_RdTmp(t1),
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(8 * VG_WORDSIZE - 1)
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU(0)
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_EmFail,
1064663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         is64 ? IRConst_U64(0) : IRConst_U32(0),
1065663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         offB_CIA
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = guest_REDIR_STACK[t1+0] */
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* PutI/GetI have I32-typed indexes regardless of guest word size */
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp(
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res,
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_GetI(descr, narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0)
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_SP = t1-1 */
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(offB_REDIR_SP, IRExpr_Binop(op_Sub, IRExpr_RdTmp(t1), one))
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to push LR and R2 onto this thread's redir stack,
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   then set R2 to the new value (which is the TOC pointer to be used
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for the duration of the replacement function, as determined by
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   m_debuginfo), and set LR to the magic return stub, so we get to
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   intercept the return and restore R2 and L2 to the values saved
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   here. */
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_push_and_set_LR_R2 ( IRSB* bb, Addr64 new_R2_value )
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64 bogus_RA  = (Addr64)&VG_(ppctoc_magic_redirect_return_stub);
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_LR   = offsetof(VexGuestPPC64State,guest_LR);
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH( bb, IRExpr_Get(offB_LR,   Ity_I64) );
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH( bb, IRExpr_Get(offB_GPR2, Ity_I64) );
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_LR,   mkU64( bogus_RA )) );
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, mkU64( new_R2_value )) );
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Platform is not TOC-afflicted, fortunately
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_pop_R2_LR_then_bLR ( IRSB* bb )
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_LR   = offsetof(VexGuestPPC64State,guest_LR);
1116663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA  = offsetof(VexGuestPPC64State,guest_CIA);
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_R2    = newIRTemp( bb->tyenv, Ity_I64 );
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_LR    = newIRTemp( bb->tyenv, Ity_I64 );
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Restore R2 */
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_R2 = gen_POP( bb );
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, IRExpr_RdTmp(old_R2)) );
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Restore LR */
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_LR = gen_POP( bb );
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_LR, IRExpr_RdTmp(old_LR)) );
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Branch to LR */
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* re boring, we arrived here precisely because a wrapped fn did a
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      blr (hence Ijk_Ret); so we should just mark this jump as Boring,
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else one _Call will have resulted in two _Rets. */
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->jumpkind = Ijk_Boring;
1130663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->next     = IRExpr_Binop(Iop_And64, IRExpr_RdTmp(old_LR), mkU64(~(3ULL)));
1131663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->offsIP   = offB_CIA;
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Platform is not TOC-afflicted, fortunately
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Since we're creating the entire IRSB right here, give it a
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      proper IMark, as it won't get one any other way, and cachegrind
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      will barf if it doesn't have one (fair enough really). */
1144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   addStmtToIRSB( bb, IRStmt_IMark( closure->readdr, 4, 0 ) );
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Generate the magic sequence:
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pop R2 from hidden stack
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pop LR from hidden stack
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto LR
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_pop_R2_LR_then_bLR(bb);
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True; /* True == this is the entire BB; don't disassemble any
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   real insns into it - just hand it directly to
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   optimiser/instrumenter/backend. */
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- END helpers for with-TOC platforms --------------- */
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the IR preamble generator used for replacement
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   functions.  It adds code to set the guest_NRADDR{_GPR2} to zero
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (technically not necessary, but facilitates detecting mixups in
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which a replacement function has been erroneously declared using
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_REPLACE_FUNCTION_Z{U,Z} when instead it should have been written
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   using VG_WRAP_FUNCTION_Z{U,Z}).
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   On with-TOC platforms the follow hacks are also done: LR and R2 are
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pushed onto a hidden stack, R2 is set to the correct value for the
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   replacement function, and LR is set to point at the magic
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return-stub address.  Setting LR causes the return of the
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wrapped/redirected function to lead to our magic return stub, which
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restores LR and R2 from said stack and returns for real.
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(get_StackTrace_wrk) understands that the LR value may point to
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the return stub address, and that in that case it can get the real
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LR value from the hidden stack instead. */
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__set_NRADDR_to_zero ( void* closureV, IRSB* bb )
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int nraddr_szB
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == VG_WORDSIZE);
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR),
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nraddr_szB == 8 ? mkU64(0) : mkU32(0)
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1191663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGP_mips32_linux)
1192663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // t9 needs to be set to point to the start of the redirected function.
1193663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1194663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1195663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1196663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     addStmtToIRSB(
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        bb,
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRStmt_Put(
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           VG_WORDSIZE==8 ? mkU64(0) : mkU32(0)
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Ditto, except set guest_NRADDR to nraddr (the un-redirected guest
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address).  This is needed for function wrapping - so the wrapper
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can read _NRADDR and find the address of the function being
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wrapped.  On toc-afflicted platforms we must also snarf r2. */
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__set_NRADDR_to_nraddr ( void* closureV, IRSB* bb )
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int nraddr_szB
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == VG_WORDSIZE);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR),
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nraddr_szB == 8
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ? IRExpr_Const(IRConst_U64( closure->nraddr ))
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            : IRExpr_Const(IRConst_U32( (UInt)closure->nraddr ))
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1233663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  if defined(VGP_mips32_linux)
1234663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // t9 needs to be set to point to the start of the redirected function.
1235663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_GPR25 = offsetof(VexGuestMIPS32State,guest_r25);
1236663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   addStmtToIRSB( bb, IRStmt_Put( offB_GPR25, mkU32( closure->readdr )) );
1237663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
1238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Get(offsetof(VexGuestArchState,guest_GPR2),
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_WORDSIZE==8 ? Ity_I64 : Ity_I32)
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Helpers to do with PPC related stack redzones. --- */
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((unused))
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool const_True ( Addr64 guest_addr )
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- main translation function --------------- */
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Note: see comments at top of m_redir.c for the Big Picture on how
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redirections are managed. */
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* normal translation, redir neither requested nor inhibited */
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Normal,
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* redir translation, function-wrap (set _NRADDR) style */
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Redir_Wrap,
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* redir translation, replacement (don't set _NRADDR) style */
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Redir_Replace,
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a translation in which redir is specifically disallowed */
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_NoRedir
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   T_Kind;
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate the basic block beginning at NRADDR, and add it to the
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translation cache & translation table.  Unless
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DEBUGGING_TRANSLATION is true, in which case the call is being done
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for debugging purposes, so (a) throw away the translation once it
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is made, and (b) produce a load of debugging output.  If
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ALLOW_REDIRECTION is False, do not attempt redirection of NRADDR,
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and also, put the resulting translation into the no-redirect tt/tc
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instead of the normal one.
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TID is the identity of the thread requesting this translation.
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(translate) ( ThreadId tid,
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Addr64   nraddr,
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool     debugging_translation,
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int      debugging_verbosity,
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ULong    bbs_done,
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool     allow_redirection )
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64             addr;
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   T_Kind             kind;
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int                tmpbuf_used, verbosity, i;
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool (*preamble_fn)(void*,IRSB*);
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexArch            vex_arch;
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexArchInfo        vex_archinfo;
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexAbiInfo         vex_abiinfo;
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestExtents    vge;
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexTranslateArgs   vta;
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexTranslateResult tres;
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure  closure;
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure Vex is initialised right. */
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Bool vex_init_done = False;
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!vex_init_done) {
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_Init ( &failure_exit, &log_bytes,
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    1,     /* debug_paranoia */
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    False, /* valgrind support */
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &VG_(clo_vex_control) );
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_init_done = True;
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Establish the translation kind and actual guest address to
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start from.  Sets (addr,kind). */
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (allow_redirection) {
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isWrap;
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr64 tmp = VG_(redir_do_lookup)( nraddr, &isWrap );
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (tmp == nraddr) {
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* no redirection found */
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = nraddr;
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kind = T_Normal;
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* found a redirect */
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = tmp;
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kind = isWrap ? T_Redir_Wrap : T_Redir_Replace;
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = nraddr;
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kind = T_NoRedir;
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Established: (nraddr, addr, kind) */
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Printing redirection info. */
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((kind == T_Redir_Wrap || kind == T_Redir_Replace)
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (VG_(clo_verbosity) >= 2 || VG_(clo_trace_redir))) {
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok;
1347663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      Char name1[512] = "";
1348663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      Char name2[512] = "";
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      name1[0] = name2[0] = 0;
1350663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ok = VG_(get_fnname_w_offset)(nraddr, name1, 512);
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok) VG_(strcpy)(name1, "???");
1352663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ok = VG_(get_fnname_w_offset)(addr, name2, 512);
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok) VG_(strcpy)(name2, "???");
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)\n",
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nraddr, name1,
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   addr, name2 );
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!debugging_translation)
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_read, Vg_CoreTranslate,
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              tid, "(translator)", addr, 1 );
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If doing any code printing, print a basic block start marker */
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_flags) || debugging_translation) {
1366663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      Char fnname[512] = "UNKNOWN_FUNCTION";
1367663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      VG_(get_fnname_w_offset)(addr, fnname, 512);
1368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      const UChar* objname = "UNKNOWN_OBJECT";
1369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      OffT         objoff  = 0;
1370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DebugInfo*   di      = VG_(find_DebugInfo)( addr );
1371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (di) {
1372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         objname = VG_(DebugInfo_get_filename)(di);
1373b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         objoff  = addr - VG_(DebugInfo_get_text_bias)(di);
1374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
1375b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(objname);
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
1377663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         "==== SB %d (evchecks %lld) [tid %d] 0x%llx %s %s+0x%llx\n",
1378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(get_bbs_translated)(), bbs_done, (Int)tid, addr,
1379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         fnname, objname, (ULong)objoff
1380b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      );
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Are we allowed to translate here? */
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { /* BEGIN new scope specially for 'seg' */
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const* seg = VG_(am_find_nsegment)(addr);
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (!translations_allowable_from_seg(seg))
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || addr == TRANSTAB_BOGUS_GUEST_ADDR ) {
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg, "translations not allowed here (0x%llx)"
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   " - throwing SEGV\n", addr);
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* U R busted, sonny.  Place your hands on your head and step
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         away from the orig_addr. */
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Code address is bad - deliver a signal instead */
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (seg != NULL) {
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* There's some kind of segment at the requested place, but we
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            aren't allowed to execute code here. */
1399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (debugging_translation)
1400b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("translations not allowed here (segment not executable)"
1401b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        "(0x%llx)\n", addr);
1402b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1403b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(synth_fault_perms)(tid, addr);
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* There is no segment at all; we are attempting to execute in
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           the middle of nowhere. */
1407b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (debugging_translation)
1408b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("translations not allowed here (no segment)"
1409b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        "(0x%llx)\n", addr);
1410b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(synth_fault_mapping)(tid, addr);
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   verbosity = 0;
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debugging_translation) {
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      verbosity = debugging_verbosity;
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (VG_(clo_trace_flags) > 0
1423663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        && VG_(get_bbs_translated)() <= VG_(clo_trace_notabove)
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && VG_(get_bbs_translated)() >= VG_(clo_trace_notbelow) )) {
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      verbosity = VG_(clo_trace_flags);
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out which preamble-mangling callback to send. */
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   preamble_fn = NULL;
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (kind == T_Redir_Replace)
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__set_NRADDR_to_zero;
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (kind == T_Redir_Wrap)
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__set_NRADDR_to_nraddr;
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ULong_to_Ptr(nraddr)
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       == (void*)&VG_(ppctoc_magic_redirect_return_stub)) {
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If entering the special return stub, this means a wrapped or
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         redirected function is returning.  Make this translation one
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         which restores R2 and LR from the thread's hidden redir
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stack, and branch to the (restored) link register, thereby
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         really causing the function to return. */
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(kind == T_Normal);
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(nraddr == addr);
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__ppctoc_magic_return_stub;
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ Actually do the translation. ------ */
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert2(VG_(tdict).tool_instrument,
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "you forgot to set VgToolInterface function 'tool_instrument'");
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the CPU info established at startup. */
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up 'abiinfo' structure with stuff Vex needs to know about
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the guest and host ABIs. */
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_default_VexAbiInfo( &vex_abiinfo );
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_stack_redzone_size = VG_STACK_REDZONE_SZB;
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_amd64_linux)
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_amd64_assume_fs_is_zero  = True;
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_amd64_darwin)
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_amd64_assume_gs_is_0x60  = True;
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc32_linux)
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_blr        = False;
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_bl         = NULL;
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.host_ppc32_regalign_int64_args = True;
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc64_linux)
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_blr        = True;
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_bl         = const_True;
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.host_ppc_calls_use_fndescrs    = True;
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up closure args. */
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.tid    = tid;
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.nraddr = nraddr;
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.readdr = addr;
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up args for LibVEX_Translate. */
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.arch_guest       = vex_arch;
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.archinfo_guest   = vex_archinfo;
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.arch_host        = vex_arch;
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.archinfo_host    = vex_archinfo;
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.abiinfo_both     = vex_abiinfo;
1491663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.callback_opaque  = (void*)&closure;
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_bytes      = (UChar*)ULong_to_Ptr(addr);
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_bytes_addr = (Addr64)addr;
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.chase_into_ok    = chase_into_ok;
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_extents    = &vge;
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes       = tmpbuf;
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes_size  = N_TMPBUF;
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes_used  = &tmpbuf_used;
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { /* At this point we have to reconcile Vex's view of the
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        instrumentation callback - which takes a void* first argument
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        - with Valgrind's view, in which the first arg is a
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VgCallbackClosure*.  Hence the following longwinded casts.
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        They are entirely legal but longwinded so as to maximise the
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        chance of the C typechecker picking up any type snafus. */
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRSB*(*f)(VgCallbackClosure*,
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRSB*,VexGuestLayout*,VexGuestExtents*,
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRType,IRType)
1508b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        = VG_(clo_vgdb) != Vg_VgdbNo
1509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             ? tool_instrument_then_gdbserver_if_needed
1510b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             : VG_(tdict).tool_instrument;
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRSB*(*g)(void*,
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRSB*,VexGuestLayout*,VexGuestExtents*,
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRType,IRType)
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       = (IRSB*(*)(void*,IRSB*,VexGuestLayout*,VexGuestExtents*,IRType,IRType))f;
1515663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     vta.instrument1     = g;
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* No need for type kludgery here. */
1518663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.instrument2       = need_to_handle_SP_assignment()
1519663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              ? vg_SP_update_pass
1520663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              : NULL;
1521663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.finaltidy         = VG_(needs).final_IR_tidy_pass
1522663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              ? VG_(tdict).tool_final_IR_tidy_pass
1523663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              : NULL;
1524663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.needs_self_check  = needs_self_check;
1525663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.preamble_function = preamble_fn;
1526663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.traceflags        = verbosity;
1527663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.addProfInc        = VG_(clo_profile_flags) > 0
1528663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                           && kind != T_NoRedir;
1529663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1530663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Set up the dispatch continuation-point info.  If this is a
1531663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      no-redir translation then it cannot be chained, and the chain-me
1532663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      points are set to NULL to indicate that.  The indir point must
1533663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      also be NULL, since we can't allow this translation to do an
1534663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      indir transfer -- that would take it back into the main
1535663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      translation cache too.
1536663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1537663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      All this is because no-redir translations live outside the main
1538663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      translation cache (in a secondary one) and chaining them would
1539663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      involve more adminstrative complexity that isn't worth the
1540663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      hassle, because we don't expect them to get used often.  So
1541663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      don't bother. */
1542663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (allow_redirection) {
1543663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_slowEP
1544663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_slowEP) );
1545663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_fastEP
1546663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_fastEP) );
1547663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_xindir
1548663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xindir) );
1549663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
1550663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_slowEP = NULL;
1551663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_fastEP = NULL;
1552663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_xindir             = NULL;
1553b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1554663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* This doesn't involve chaining and so is always allowable. */
1555663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.disp_cp_xassisted
1556663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xassisted) );
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Sheesh.  Finally, actually _do_ the translation! */
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tres = LibVEX_Translate ( &vta );
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1561b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(tres.status == VexTransOK);
1562b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(tres.n_sc_extents >= 0 && tres.n_sc_extents <= 3);
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used <= N_TMPBUF);
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used > 0);
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell aspacem of all segments that have had translations taken
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from them.  Optimisation: don't re-look up vge.base[0] since seg
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should already point to it. */
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( vge.base[0] == (Addr64)addr );
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* set 'translations taken from this segment' flag */
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( (NSegment*)seg );
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* END new scope specially for 'seg' */
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < vge.n_used; i++) {
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NSegment const* seg
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = VG_(am_find_nsegment)( vge.base[i] );
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set 'translations taken from this segment' flag */
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( (NSegment*)seg );
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy data at trans_addr into the translation cache. */
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // If debugging, don't do anything with the translated block;  we
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only did this for the debugging output produced along the way.
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!debugging_translation) {
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (kind != T_NoRedir) {
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // Put it into the normal TT/TC structures.  This is the
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // normal case.
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // Note that we use nraddr (the non-redirected address), not
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // addr, which might have been changed by the redirection
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          VG_(add_to_transtab)( &vge,
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nraddr,
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                (Addr)(&tmpbuf[0]),
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                tmpbuf_used,
1599663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.n_sc_extents > 0,
1600663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.offs_profInc,
1601663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.n_guest_instrs,
1602663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                vex_arch );
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1604663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng          vg_assert(tres.offs_profInc == -1); /* -1 == unset */
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          VG_(add_to_unredir_transtab)( &vge,
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        nraddr,
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        (Addr)(&tmpbuf[0]),
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        tmpbuf_used );
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1618