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
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2000-2013 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}
48436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#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
64436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "libvex_emnote.h"        // For PPC, EmWarn_PPC64_redir_underflow
65436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Stats                                                ---*/
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_fast            = 0;
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_generic_known   = 0;
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt n_SP_updates_generic_unknown = 0;
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(print_translation_stats) ( void )
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
76436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   HChar buf[7];
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         + n_SP_updates_generic_unknown;
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate:            fast SP updates identified: %'u (%s)\n",
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_fast, buf );
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate:   generic_known SP updates identified: %'u (%s)\n",
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_generic_known, buf );
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(percentify)(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(message)(Vg_DebugMsg,
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "translate: generic_unknown SP updates identified: %'u (%s)\n",
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_SP_updates_generic_unknown, buf );
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- %SP-update pass                                      ---*/
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool need_to_handle_SP_assignment(void)
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ( VG_(tdict).track_new_mem_stack_4   ||
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_4   ||
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_8   ||
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_8   ||
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_12  ||
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_12  ||
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_16  ||
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_16  ||
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_32  ||
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_32  ||
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_112 ||
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_112 ||
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_128 ||
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_128 ||
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_144 ||
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_144 ||
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack_160 ||
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack_160 ||
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_new_mem_stack     ||
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(tdict).track_die_mem_stack     );
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - The SP aliases are held in an array which is used as a circular buffer.
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   This misses very few constant updates of SP (ie. < 0.1%) while using a
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   small, constant structure that will also never fill up and cause
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   execution to abort.
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Unused slots have a .temp value of 'IRTemp_INVALID'.
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - 'next_SP_alias_slot' is the index where the next alias will be stored.
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - If the buffer fills, we circle around and start over-writing
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   non-IRTemp_INVALID values.  This is rare, and the overwriting of a
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   value that would have subsequently be used is even rarer.
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// - Every slot below next_SP_alias_slot holds a non-IRTemp_INVALID value.
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   The rest either all won't (if we haven't yet circled around) or all
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   will (if we have circled around).
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp temp;
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Long   delta;
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_Alias;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// With 32 slots the buffer fills very rarely -- eg. once in a run of GCC.
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// And I've tested with smaller values and the wrap-around case works ok.
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_ALIASES    32
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SP_Alias SP_aliases[N_ALIASES];
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int      next_SP_alias_slot = 0;
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void clear_SP_aliases(void)
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < N_ALIASES; i++) {
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].temp  = IRTemp_INVALID;
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].delta = 0;
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_SP_alias_slot = 0;
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void add_SP_alias(IRTemp temp, Long delta)
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(temp != IRTemp_INVALID);
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_aliases[ next_SP_alias_slot ].temp  = temp;
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SP_aliases[ next_SP_alias_slot ].delta = delta;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   next_SP_alias_slot++;
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (N_ALIASES == next_SP_alias_slot) next_SP_alias_slot = 0;
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool get_SP_delta(IRTemp temp, Long* delta)
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;      // i must be signed!
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(IRTemp_INVALID != temp);
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Search backwards between current buffer position and the start.
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = next_SP_alias_slot-1; i >= 0; i--) {
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (temp == SP_aliases[i].temp) {
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *delta = SP_aliases[i].delta;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Search backwards between the end and the current buffer position.
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = N_ALIASES-1; i >= next_SP_alias_slot; i--) {
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (temp == SP_aliases[i].temp) {
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *delta = SP_aliases[i].delta;
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void update_SP_aliases(Long delta)
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < N_ALIASES; i++) {
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (SP_aliases[i].temp == IRTemp_INVALID) {
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return;
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SP_aliases[i].delta += delta;
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given a guest IP, get an origin tag for a 1-element stack trace,
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and wrap it up in an IR atom that can be passed as the origin-tag
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value for a stack-adjustment helper function. */
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_ecu_Expr ( Addr64 guest_IP )
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt ecu;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ExeContext* ec
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = VG_(make_depth_1_ExeContext_from_Addr)( (Addr)guest_IP );
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ec);
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ecu = VG_(get_ECU_from_ExeContext)( ec );
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_plausible_ECU)(ecu));
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is always safe to do, since ecu is only 32 bits, and
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HWord is 32 or 64. */
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkIRExpr_HWord( (HWord)ecu );
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* When gdbserver is activated, the translation of a block must
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   first be done by the tool function, then followed by a pass
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   which (if needed) instruments the code for gdbserver.
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovIRSB* tool_instrument_then_gdbserver_if_needed ( VgCallbackClosure* closureV,
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRSB*              sb_in,
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 VexGuestLayout*    layout,
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 VexGuestExtents*   vge,
225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                                 VexArchInfo*       vai,
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRType             gWordTy,
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                                 IRType             hWordTy )
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return VG_(instrument_for_gdbserver_if_needed)
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (VG_(tdict).tool_instrument (closureV,
231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   sb_in,
232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   layout,
233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   vge,
234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                   vai,
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   gWordTy,
236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   hWordTy),
237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       layout,
238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       vge,
239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       gWordTy,
240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       hWordTy);
241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For tools that want to know about SP changes, this pass adds
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in the appropriate hooks.  We have to do it after the tool's
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instrumentation, so the tool doesn't have to worry about the C calls
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it adds in, and we must do it before register allocation because
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   spilled temps make it much harder to work out the SP deltas.
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This it is done with Vex's "second instrumentation" pass.
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Basically, we look for GET(SP)/PUT(SP) pairs and track constant
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   increments/decrements of SP between them.  (This requires tracking one or
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   more "aliases", which are not exact aliases but instead are tempregs
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whose value is equal to the SP's plus or minus a known constant.)
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If all the changes to SP leading up to a PUT(SP) are by known, small
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constants, we can do a specific call to eg. new_mem_stack_4, otherwise
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   we fall back to the case that handles an unknown SP change.
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There is some extra complexity to deal correctly with updates to
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only parts of SP.  Bizarre, but it has been known to happen.
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRSB* vg_SP_update_pass ( void*             closureV,
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRSB*             sb_in,
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VexGuestLayout*   layout,
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VexGuestExtents*  vge,
266436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          VexArchInfo*      vai,
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRType            gWordTy,
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          IRType            hWordTy )
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
270663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int         i, j, k, minoff_ST, maxoff_ST, sizeof_SP, offset_SP;
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         first_SP, last_SP, first_Put, last_Put;
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRDirty     *dcall, *d;
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRStmt*     st;
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     e;
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType      typeof_SP;
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long        delta, con;
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up stuff for tracking the guest IP */
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   curr_IP_known = False;
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64 curr_IP       = 0;
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up BB */
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRSB* bb     = emptyIRSB();
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->tyenv    = deepCopyIRTypeEnv(sb_in->tyenv);
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->next     = deepCopyIRExpr(sb_in->next);
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->jumpkind = sb_in->jumpkind;
288663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->offsIP   = sb_in->offsIP;
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta = 0;
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sizeof_SP = layout->sizeof_SP;
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   offset_SP = layout->offset_SP;
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   typeof_SP = sizeof_SP==4 ? Ity_I32 : Ity_I64;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof_SP == 4 || sizeof_SP == 8);
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- Start of #defines --- */
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_ADD(op) (sizeof_SP==4 ? ((op)==Iop_Add32) : ((op)==Iop_Add64))
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_SUB(op) (sizeof_SP==4 ? ((op)==Iop_Sub32) : ((op)==Iop_Sub64))
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define IS_ADD_OR_SUB(op) (IS_ADD(op) || IS_SUB(op))
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define GET_CONST(con)                                                \
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       (sizeof_SP==4 ? (Long)(Int)(con->Ico.U32)                        \
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : (Long)(con->Ico.U64))
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO_NEW(syze, tmpp)                                            \
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do {                                                              \
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool vanilla, w_ecu;                                           \
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(curr_IP_known);                                      \
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vanilla = NULL != VG_(tdict).track_new_mem_stack_##syze;       \
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         w_ecu   = NULL != VG_(tdict).track_new_mem_stack_##syze##_w_ECU; \
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(!(vanilla && w_ecu)); /* can't have both */          \
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(vanilla || w_ecu))                                       \
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto generic;                                               \
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* I don't know if it's really necessary to say that the */    \
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* call reads the stack pointer.  But anyway, we do. */        \
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (w_ecu) {                                                   \
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(                                  \
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       2/*regparms*/,                                   \
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "track_new_mem_stack_" #syze "_w_ECU",           \
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)(                           \
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VG_(tdict).track_new_mem_stack_##syze##_w_ECU ), \
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_2(IRExpr_RdTmp(tmpp),                \
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mk_ecu_Expr(curr_IP))              \
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );                                                  \
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {                                                       \
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dcall = unsafeIRDirty_0_N(                                  \
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       1/*regparms*/,                                   \
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "track_new_mem_stack_" #syze ,                   \
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(fnptr_to_fnentry)(                           \
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          VG_(tdict).track_new_mem_stack_##syze ),      \
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_1(IRExpr_RdTmp(tmpp))                \
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    );                                                  \
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }                                                              \
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->nFxState = 1;                                           \
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].fx     = Ifx_Read;                           \
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].offset = layout->offset_SP;                  \
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].size   = layout->sizeof_SP;                  \
342663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].nRepeats  = 0;                               \
343663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].repeatLen = 0;                               \
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( bb, IRStmt_Dirty(dcall) );                      \
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(syze > 0);                                           \
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_SP_aliases(syze);                                       \
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_fast++;                                           \
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } while (0)
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define DO_DIE(syze, tmpp)                                            \
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do {                                                              \
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!VG_(tdict).track_die_mem_stack_##syze)                    \
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto generic;                                               \
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* I don't know if it's really necessary to say that the */    \
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* call reads the stack pointer.  But anyway, we do. */        \
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall = unsafeIRDirty_0_N(                                     \
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    1/*regparms*/,                                      \
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "track_die_mem_stack_" #syze,                       \
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_(fnptr_to_fnentry)(                              \
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       VG_(tdict).track_die_mem_stack_##syze ),         \
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkIRExprVec_1(IRExpr_RdTmp(tmpp))                   \
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );                                                     \
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->nFxState = 1;                                           \
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].fx     = Ifx_Read;                           \
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].offset = layout->offset_SP;                  \
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dcall->fxState[0].size   = layout->sizeof_SP;                  \
372663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].nRepeats  = 0;                               \
373663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         dcall->fxState[0].repeatLen = 0;                               \
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB( bb, IRStmt_Dirty(dcall) );                      \
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(syze > 0);                                           \
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         update_SP_aliases(-(syze));                                    \
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_fast++;                                           \
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                                        \
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } while (0)
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- End of #defines --- */
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   clear_SP_aliases();
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i <  sb_in->stmts_used; i++) {
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st = sb_in->stmts[i];
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_IMark) {
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_IP_known = True;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         curr_IP       = st->Ist.IMark.addr;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t = Get(sp):   curr = t, delta = 0 */
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case2;
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_Get)              goto case2;
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Get.offset != offset_SP) goto case2;
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Get.ty != typeof_SP)     goto case2;
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_SP_alias(st->Ist.WrTmp.tmp, 0);
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case2:
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t' = curr +/- const:   curr = t',  delta +=/-= const */
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case3;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_Binop) goto case3;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Binop.arg1->tag != Iex_RdTmp) goto case3;
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!get_SP_delta(e->Iex.Binop.arg1->Iex.RdTmp.tmp, &delta)) goto case3;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->Iex.Binop.arg2->tag != Iex_Const) goto case3;
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!IS_ADD_OR_SUB(e->Iex.Binop.op)) goto case3;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      con = GET_CONST(e->Iex.Binop.arg2->Iex.Const.con);
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (IS_ADD(e->Iex.Binop.op)) {
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         add_SP_alias(st->Ist.WrTmp.tmp, delta + con);
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         add_SP_alias(st->Ist.WrTmp.tmp, delta - con);
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case3:
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t' = curr:   curr = t' */
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_WrTmp) goto case4;
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = st->Ist.WrTmp.data;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (e->tag != Iex_RdTmp) goto case4;
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!get_SP_delta(e->Iex.RdTmp.tmp, &delta)) goto case4;
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.WrTmp.tmp) == typeof_SP );
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add_SP_alias(st->Ist.WrTmp.tmp, delta);
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      continue;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case4:
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Put(sp) = curr */
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* More generally, we must correctly handle a Put which writes
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any part of SP, not just the case where all of SP is
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         written. */
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag != Ist_Put) goto case5;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      first_SP  = offset_SP;
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      last_SP   = first_SP + sizeof_SP - 1;
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      first_Put = st->Ist.Put.offset;
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      last_Put  = first_Put
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  + sizeofIRType( typeOfIRExpr( bb->tyenv, st->Ist.Put.data ))
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  - 1;
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(first_SP <= last_SP);
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(first_Put <= last_Put);
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (last_Put < first_SP || last_SP < first_Put)
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto case5; /* no overlap */
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->Ist.Put.data->tag == Iex_RdTmp
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && get_SP_delta(st->Ist.Put.data->Iex.RdTmp.tmp, &delta)) {
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp tttmp = st->Ist.Put.data->Iex.RdTmp.tmp;
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Why should the following assertion hold?  Because any
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            alias added by put_SP_alias must be of a temporary which
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            has the same type as typeof_SP, and whose value is a Get
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            at exactly offset_SP of size typeof_SP.  Each call to
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            put_SP_alias is immediately preceded by an assertion that
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we are putting in a binding for a correctly-typed
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            temporary. */
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert( typeOfIRTemp(bb->tyenv, tttmp) == typeof_SP );
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* From the same type-and-offset-correctness argument, if
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we found a useable alias, it must for an "exact" write of SP. */
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(first_SP == first_Put);
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(last_SP == last_Put);
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (delta) {
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    0:                      addStmtToIRSB(bb,st); continue;
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    4: DO_DIE(  4,  tttmp); addStmtToIRSB(bb,st); continue;
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   -4: DO_NEW(  4,  tttmp); addStmtToIRSB(bb,st); continue;
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case    8: DO_DIE(  8,  tttmp); addStmtToIRSB(bb,st); continue;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   -8: DO_NEW(  8,  tttmp); addStmtToIRSB(bb,st); continue;
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   12: DO_DIE(  12, tttmp); addStmtToIRSB(bb,st); continue;
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -12: DO_NEW(  12, tttmp); addStmtToIRSB(bb,st); continue;
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   16: DO_DIE(  16, tttmp); addStmtToIRSB(bb,st); continue;
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -16: DO_NEW(  16, tttmp); addStmtToIRSB(bb,st); continue;
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case   32: DO_DIE(  32, tttmp); addStmtToIRSB(bb,st); continue;
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  -32: DO_NEW(  32, tttmp); addStmtToIRSB(bb,st); continue;
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  112: DO_DIE( 112, tttmp); addStmtToIRSB(bb,st); continue;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -112: DO_NEW( 112, tttmp); addStmtToIRSB(bb,st); continue;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  128: DO_DIE( 128, tttmp); addStmtToIRSB(bb,st); continue;
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -128: DO_NEW( 128, tttmp); addStmtToIRSB(bb,st); continue;
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  144: DO_DIE( 144, tttmp); addStmtToIRSB(bb,st); continue;
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -144: DO_NEW( 144, tttmp); addStmtToIRSB(bb,st); continue;
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case  160: DO_DIE( 160, tttmp); addStmtToIRSB(bb,st); continue;
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case -160: DO_NEW( 160, tttmp); addStmtToIRSB(bb,st); continue;
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* common values for ppc64: 144 128 160 112 176 */
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               n_SP_updates_generic_known++;
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto generic;
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Deal with an unknown update to SP.  We're here because
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            either:
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (1) the Put does not exactly cover SP; it is a partial update.
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Highly unlikely, but has been known to happen for 16-bit
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Windows apps running on Wine, doing 16-bit adjustments to
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                %sp.
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (2) the Put does exactly cover SP, but we are unable to
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                determine how the value relates to the old SP.  In any
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                case, we cannot assume that the Put.data value is a tmp;
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                we must assume it can be anything allowed in flat IR (tmp
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                or const).
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  old_SP;
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         n_SP_updates_generic_unknown++;
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // Nb: if all is well, this generic case will typically be
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // called something like every 1000th SP update.  If it's more than
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // that, the above code may be missing some cases.
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        generic:
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Pass both the old and new SP values to this helper.  Also,
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pass an origin tag, even if it isn't needed. */
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old_SP = newIRTemp(bb->tyenv, typeof_SP);
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addStmtToIRSB(
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bb,
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRStmt_WrTmp( old_SP, IRExpr_Get(offset_SP, typeof_SP) )
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now we know what the old value of SP is.  But knowing the new
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            value is a bit tricky if there is a partial write. */
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (first_Put == first_SP && last_Put == last_SP) {
527436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            /* The common case, an exact write to SP.  So st->Ist.Put.data
528436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               does hold the new value; simple. */
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(curr_IP_known);
530436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            if (NULL != VG_(tdict).track_new_mem_stack_w_ECU)
531436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               dcall = unsafeIRDirty_0_N(
532436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          3/*regparms*/,
533436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          "VG_(unknown_SP_update_w_ECU)",
534436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update_w_ECU) ),
535436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          mkIRExprVec_3( IRExpr_RdTmp(old_SP), st->Ist.Put.data,
536436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         mk_ecu_Expr(curr_IP) )
537436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       );
538436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            else
539436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               dcall = unsafeIRDirty_0_N(
540436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          2/*regparms*/,
541436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          "VG_(unknown_SP_update)",
542436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
543436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          mkIRExprVec_2( IRExpr_RdTmp(old_SP), st->Ist.Put.data )
544436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       );
545436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* don't forget the original assignment */
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, st );
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* We have a partial update to SP.  We need to know what
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the new SP will be, and hand that to the helper call,
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               but when the helper call happens, SP must hold the
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               value it had before the update.  Tricky.
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Therefore use the following kludge:
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               1. do the partial SP update (Put)
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               2. Get the new SP value into a tmp, new_SP
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               3. Put old_SP
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               4. Call the helper
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               5. Put new_SP
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            */
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp new_SP;
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 1 */
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, st );
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 2 */
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            new_SP = newIRTemp(bb->tyenv, typeof_SP);
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB(
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               bb,
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRStmt_WrTmp( new_SP, IRExpr_Get(offset_SP, typeof_SP) )
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 3 */
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(old_SP) ));
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 4 */
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert(curr_IP_known);
574436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            if (NULL != VG_(tdict).track_new_mem_stack_w_ECU)
575436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               dcall = unsafeIRDirty_0_N(
576436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          3/*regparms*/,
577436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          "VG_(unknown_SP_update_w_ECU)",
578436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update_w_ECU) ),
579436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          mkIRExprVec_3( IRExpr_RdTmp(old_SP),
580436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         IRExpr_RdTmp(new_SP),
581436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         mk_ecu_Expr(curr_IP) )
582436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       );
583436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            else
584436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               dcall = unsafeIRDirty_0_N(
585436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          2/*regparms*/,
586436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          "VG_(unknown_SP_update)",
587436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          VG_(fnptr_to_fnentry)( &VG_(unknown_SP_update) ),
588436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                          mkIRExprVec_2( IRExpr_RdTmp(old_SP),
589436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                         IRExpr_RdTmp(new_SP) )
590436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                       );
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Dirty(dcall) );
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* 5 */
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addStmtToIRSB( bb, IRStmt_Put(offset_SP, IRExpr_RdTmp(new_SP) ));
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Forget what we already know. */
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         clear_SP_aliases();
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If this is a Put of a tmp that exactly updates SP,
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            start tracking aliases against this tmp. */
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (first_Put == first_SP && last_Put == last_SP
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && st->Ist.Put.data->tag == Iex_RdTmp) {
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vg_assert( typeOfIRTemp(bb->tyenv, st->Ist.Put.data->Iex.RdTmp.tmp)
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       == typeof_SP );
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            add_SP_alias(st->Ist.Put.data->Iex.RdTmp.tmp, 0);
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         continue;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     case5:
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PutI or Dirty call which overlaps SP: complain.  We can't
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         deal with SP changing in weird ways (well, we can, but not at
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this time of night).  */
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_PutI) {
616663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         descr = st->Ist.PutI.details->descr;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         minoff_ST = descr->base;
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maxoff_ST = descr->base
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     + descr->nElems * sizeofIRType(descr->elemTy) - 1;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(offset_SP > maxoff_ST
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               || (offset_SP + sizeof_SP - 1) < minoff_ST))
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto complain;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (st->tag == Ist_Dirty) {
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d = st->Ist.Dirty.details;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         for (j = 0; j < d->nFxState; j++) {
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (d->fxState[j].fx == Ifx_Read || d->fxState[j].fx == Ifx_None)
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue;
629663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            /* Enumerate the described state segments */
630663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            for (k = 0; k < 1 + d->fxState[j].nRepeats; k++) {
631663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               minoff_ST = d->fxState[j].offset + k * d->fxState[j].repeatLen;
632663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               maxoff_ST = minoff_ST + d->fxState[j].size - 1;
633663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng               if (!(offset_SP > maxoff_ST
634663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                     || (offset_SP + sizeof_SP - 1) < minoff_ST))
635663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                  goto complain;
636663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            }
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* well, not interesting.  Just copy and keep going. */
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addStmtToIRSB( bb, st );
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* for (i = 0; i < sb_in->stmts_used; i++) */
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return bb;
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  complain:
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(core_panic)("vg_SP_update_pass: PutI or Dirty which overlaps SP");
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_ADD
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_SUB
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef IS_ADD_OR_SUB
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef GET_CONST
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DO_NEW
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DO_DIE
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Main entry point for the JITter.                     ---*/
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extra comments re self-checking translations and self-modifying
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   code.  (JRS 14 Oct 05).
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are 3 modes:
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (1) no checking: all code assumed to be not self-modifying
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (2) partial: known-problematic situations get a self-check
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (3) full checking: all translations get a self-check
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   As currently implemented, the default is (2).  (3) is always safe,
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   but very slow.  (1) works mostly, but fails for gcc nested-function
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   code which uses trampolines on the stack; this situation is
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   detected and handled by (2).
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A more robust and transparent solution, which is not currently
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implemented, is a variant of (2): if a translation is made from an
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   area which aspacem says does not have 'w' permission, then it can
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be non-self-checking.  Otherwise, it needs a self-check.
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This is complicated by Vex's basic-block chasing.  If a self-check
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is requested, then Vex will not chase over basic block boundaries
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (it's too complex).  However there is still a problem if it chases
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from a non-'w' area into a 'w' area.
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   I think the right thing to do is:
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - if a translation request starts in a 'w' area, ask for a
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     self-checking translation, and do not allow any chasing (make
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     chase_into_ok return False).  Note that the latter is redundant
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     in the sense that Vex won't chase anyway in this situation.
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - if a translation request starts in a non-'w' area, do not ask for
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     a self-checking translation.  However, do not allow chasing (as
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     determined by chase_into_ok) to go into a 'w' area.
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The result of this is that all code inside 'w' areas is self
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   checking.
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   To complete the trick, there is a caveat: we must watch the
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   client's mprotect calls.  If pages are changed from non-'w' to 'w'
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   then we should throw away all translations which intersect the
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   affected area, so as to force them to be redone with self-checks.
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ----------
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The above outlines the conditions under which bb chasing is allowed
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from a self-modifying-code point of view.  There are other
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   situations pertaining to function redirection in which it is
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   necessary to disallow chasing, but those fall outside the scope of
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this comment.
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vex dumps the final code in here.  Then we can copy it off
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wherever we like. */
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 60000: should agree with assertion in VG_(add_to_transtab) in
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   m_transtab.c. */
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define N_TMPBUF 60000
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar tmpbuf[N_TMPBUF];
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Function pointers we must supply to LibVEX in order that it
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can bomb out and emit messages under Valgrind's control. */
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__ ((noreturn))
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid failure_exit ( void )
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_ShowAllocStats();
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(core_panic)("LibVEX called failure_exit().");
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid log_bytes ( HChar* bytes, Int nbytes )
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Int i;
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (i = 0; i < nbytes-3; i += 4)
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(printf)("%c%c%c%c", bytes[i], bytes[i+1], bytes[i+2], bytes[i+3]);
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (; i < nbytes; i++)
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VG_(printf)("%c", bytes[i]);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Various helper functions for translation --------- */
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Look for reasons to disallow making translations from the given
748436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   segment/addr. */
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
750436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic Bool translations_allowable_from_seg ( NSegment const* seg, Addr addr )
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
752436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGA_x86) || defined(VGA_s390x) || defined(VGA_mips32) \
753436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      || defined(VGA_mips64)
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool allowR = True;
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool allowR = False;
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return seg != NULL
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (seg->kind == SkAnonC || seg->kind == SkFileC || seg->kind == SkShmC)
760436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          && (seg->hasX
761436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov              || (seg->hasR && (allowR
762436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                || VG_(has_gdbserver_breakpoint) (addr))));
763436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* If GDB/gdbsrv has inserted a breakpoint at addr, assume this is a valid
764436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      location to translate if seg is not executable but is readable.
765436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      This is needed for inferior function calls from GDB: GDB inserts a
766436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      breakpoint on the stack, and expects to regain control before the
767436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      breakpoint instruction at the breakpoint address is really
768436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      executed. For this, the breakpoint instruction must be translated
769436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      so as to have the call to gdbserver executed. */
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Produce a bitmask stating which of the supplied extents needs a
774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   self-check.  See documentation of
775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexTranslateArgs::needs_self_check for more details about the
776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return convention. */
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
778b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic UInt needs_self_check ( void* closureV,
779b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                               VexGuestExtents* vge )
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UInt i, bitset;
783b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
784b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(vge->n_used >= 1 && vge->n_used <= 3);
785b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   bitset = 0;
786b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
787b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < vge->n_used; i++) {
788b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Bool  check = False;
789b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Addr  addr  = (Addr)vge->base[i];
790b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      SizeT len   = (SizeT)vge->len[i];
791b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      NSegment const* segA = NULL;
792b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
793b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#     if defined(VGO_darwin)
794b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // GrP fixme hack - dyld i386 IMPORT gets rewritten.
795b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // To really do this correctly, we'd need to flush the
796b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      // translation cache whenever a segment became +WX.
797b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      segA = VG_(am_find_nsegment)(addr);
798b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (segA && segA->hasX && segA->hasW)
799b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         check = True;
800b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#     endif
801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (!check) {
803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         switch (VG_(clo_smc_check)) {
804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcNone:
805b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* never check (except as per Darwin hack above) */
806b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
807b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcAll:
808b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* always check */
809b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               check = True;
810b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
811b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcStack: {
812b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* check if the address is in the same segment as this
813b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  thread's stack pointer */
814b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               Addr sp = VG_(get_SP)(closure->tid);
815b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (!segA) {
816b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  segA = VG_(am_find_nsegment)(addr);
817b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
818b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               NSegment const* segSP = VG_(am_find_nsegment)(sp);
819b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (segA && segSP && segA == segSP)
820b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  check = True;
821b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
822b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
823b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            case Vg_SmcAllNonFile: {
824b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               /* check if any part of the extent is not in a
825b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  file-mapped segment */
826b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (!segA) {
827b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  segA = VG_(am_find_nsegment)(addr);
828b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
829b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               if (segA && segA->kind == SkFileC && segA->start <= addr
830b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                   && (len == 0 || addr + len <= segA->end + 1)) {
831b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  /* in a file-mapped segment; skip the check */
832b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               } else {
833b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  check = True;
834b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               }
835b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               break;
836b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
837b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            default:
838b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               vg_assert(0);
839b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
840b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
841b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
842b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (check)
843b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         bitset |= (1 << i);
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
845b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
846b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return bitset;
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is a callback passed to LibVEX_Translate.  It stops Vex from
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   chasing into function entry points that we wish to redirect.
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Chasing across them obviously defeats the redirect mechanism, with
853b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   bad effects for Memcheck, Helgrind, DRD, Massif, and possibly others.
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool chase_into_ok ( void* closureV, Addr64 addr64 )
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr               addr    = (Addr)addr64;
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const*    seg     = VG_(am_find_nsegment)(addr);
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Work through a list of possibilities why we might not want to
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allow a chase. */
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Destination not in a plausible segment? */
864436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!translations_allowable_from_seg(seg, addr))
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Destination is redirected? */
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addr != VG_(redir_do_lookup)(addr, NULL))
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This needs to be at the start of its own block.  Don't chase. Re
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong_to_Ptr, be careful to ensure we only compare 32 bits on a
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      32-bit target.*/
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ULong_to_Ptr(addr64)
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       == (void*)&VG_(ppctoc_magic_redirect_return_stub))
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* overly conservative, but .. don't chase into the distinguished
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      address that m_transtab uses as an empty-slot marker for
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(tt_fast). */
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addr == TRANSTAB_BOGUS_GUEST_ADDR)
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto dontchase;
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGA_s390x)
887b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Never chase into an EX instruction. Generating IR for EX causes
888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      a round-trip through the scheduler including VG_(discard_translations).
889b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      And that's expensive as shown by perf/tinycc.c:
890b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Chasing into EX increases the number of EX translations from 21 to
891b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      102666 causing a 7x runtime increase for "none" and a 3.2x runtime
892b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      increase for memcheck. */
893b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (((UChar *)ULong_to_Ptr(addr))[0] == 0x44 ||   /* EX */
894b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       ((UChar *)ULong_to_Ptr(addr))[0] == 0xC6)     /* EXRL */
895b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     goto dontchase;
896b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  endif
897b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* well, ok then.  go on and chase. */
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  dontchase:
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) VG_(printf)("not chasing into 0x%lx\n", addr);
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- helpers for with-TOC platforms --------------- */
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
912b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* NOTE: with-TOC platforms are: ppc64-linux. */
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong n ) {
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(n));
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( UInt n ) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32(n));
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VG_PLAT_USES_PPCTOC)
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( UChar n ) {
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8(n));
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* narrowTo32 ( IRTypeEnv* tyenv, IRExpr* e ) {
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (typeOfIRExpr(tyenv, e) == Ity_I32) {
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(typeOfIRExpr(tyenv, e) == Ity_I64);
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return IRExpr_Unop(Iop_64to32, e);
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to push word-typed expression 'e' onto this thread's
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redir stack, checking for stack overflow and generating code to
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bomb out if so. */
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_PUSH ( IRSB* bb, IRExpr* e )
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      t1;
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     one;
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
944b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC64State,guest_REDIR_SP);
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
948436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int    offB_EMNOTE      = offsetof(VexGuestPPC64State,guest_EMNOTE);
949663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC64State,guest_CIA);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = True;
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I64;
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE64;
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar64;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub64;
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Add           = Iop_Add64;
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(ULong)    = mkU64;
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_WORDSIZE == 8);
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC32State,guest_REDIR_SP);
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
962436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int    offB_EMNOTE      = offsetof(VexGuestPPC32State,guest_EMNOTE);
963663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC32State,guest_CIA);
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = False;
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I32;
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE32;
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar32;
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub32;
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Add           = Iop_Add32;
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(UInt)     = mkU32;
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_WORDSIZE == 4);
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(void*) == VG_WORDSIZE);
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Word)  == VG_WORDSIZE);
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Addr)  == VG_WORDSIZE);
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t1    = newIRTemp( bb->tyenv, ty_Word );
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   one   = mkU(1);
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(typeOfIRExpr(bb->tyenv, e) == ty_Word);
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 = guest_REDIR_SP + 1 */
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp(
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1,
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(op_Add, IRExpr_Get( offB_REDIR_SP, ty_Word ), one)
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bomb out if t1 >=s stack_size, that is, (stack_size-1)-t1 <s 0.
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The destination (0) is a bit bogus but it doesn't matter since
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this is an unrecoverable error and will lead to Valgrind
996436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      shutting down.  _EMNOTE is set regardless - that's harmless
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since is only has a meaning if the exit is taken. */
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1000436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_overflow))
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op_CmpNE,
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Binop(
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op_Sar,
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Binop(op_Sub,mkU(stack_size-1),IRExpr_RdTmp(t1)),
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(8 * VG_WORDSIZE - 1)
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU(0)
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_EmFail,
1015663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         is64 ? IRConst_U64(0) : IRConst_U32(0),
1016663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         offB_CIA
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_SP = t1 */
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(bb, IRStmt_Put(offB_REDIR_SP, IRExpr_RdTmp(t1)));
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_STACK[t1+0] = e */
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* PutI/GetI have I32-typed indexes regardless of guest word size */
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1027663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      IRStmt_PutI(mkIRPutI(descr,
1028663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                           narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0, e)));
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to pop a word-sized value from this thread's redir
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack, binding it to a new temporary, which is returned.  As with
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH, an overflow check is also performed. */
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_POP ( IRSB* bb )
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1038b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC64_REDIR_STACK_SIZE;
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC64State,guest_REDIR_SP);
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC64State,guest_REDIR_STACK);
1042436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int    offB_EMNOTE      = offsetof(VexGuestPPC64State,guest_EMNOTE);
1043663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC64State,guest_CIA);
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = True;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I64;
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE64;
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar64;
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub64;
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(ULong)    = mkU64;
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    stack_size       = VEX_GUEST_PPC32_REDIR_STACK_SIZE;
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_SP    = offsetof(VexGuestPPC32State,guest_REDIR_SP);
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_REDIR_STACK = offsetof(VexGuestPPC32State,guest_REDIR_STACK);
1054436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int    offB_EMNOTE      = offsetof(VexGuestPPC32State,guest_EMNOTE);
1055663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA         = offsetof(VexGuestPPC32State,guest_CIA);
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   is64             = False;
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty_Word          = Ity_I32;
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_CmpNE         = Iop_CmpNE32;
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sar           = Iop_Sar32;
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   op_Sub           = Iop_Sub32;
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*(*mkU)(UInt)     = mkU32;
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( offB_REDIR_STACK, ty_Word, stack_size );
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      t1    = newIRTemp( bb->tyenv, ty_Word );
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp      res   = newIRTemp( bb->tyenv, ty_Word );
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     one   = mkU(1);
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(void*) == VG_WORDSIZE);
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Word)  == VG_WORDSIZE);
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sizeof(Addr)  == VG_WORDSIZE);
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t1 = guest_REDIR_SP */
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp( t1, IRExpr_Get( offB_REDIR_SP, ty_Word ) )
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bomb out if t1 < 0.  Same comments as gen_PUSH apply. */
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1082436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      IRStmt_Put(offB_EMNOTE, mkU32(EmWarn_PPC64_redir_underflow))
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Binop(
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            op_CmpNE,
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Binop(
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               op_Sar,
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_RdTmp(t1),
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(8 * VG_WORDSIZE - 1)
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkU(0)
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_EmFail,
1097663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         is64 ? IRConst_U64(0) : IRConst_U32(0),
1098663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         offB_CIA
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* res = guest_REDIR_STACK[t1+0] */
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* PutI/GetI have I32-typed indexes regardless of guest word size */
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_WrTmp(
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         res,
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_GetI(descr, narrowTo32(bb->tyenv,IRExpr_RdTmp(t1)), 0)
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* guest_REDIR_SP = t1-1 */
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(offB_REDIR_SP, IRExpr_Binop(op_Sub, IRExpr_RdTmp(t1), one))
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to push LR and R2 onto this thread's redir stack,
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   then set R2 to the new value (which is the TOC pointer to be used
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for the duration of the replacement function, as determined by
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   m_debuginfo), and set LR to the magic return stub, so we get to
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   intercept the return and restore R2 and L2 to the values saved
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   here. */
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_push_and_set_LR_R2 ( IRSB* bb, Addr64 new_R2_value )
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64 bogus_RA  = (Addr64)&VG_(ppctoc_magic_redirect_return_stub);
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_LR   = offsetof(VexGuestPPC64State,guest_LR);
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH( bb, IRExpr_Get(offB_LR,   Ity_I64) );
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_PUSH( bb, IRExpr_Get(offB_GPR2, Ity_I64) );
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_LR,   mkU64( bogus_RA )) );
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, mkU64( new_R2_value )) );
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Platform is not TOC-afflicted, fortunately
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_pop_R2_LR_then_bLR ( IRSB* bb )
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_GPR2 = offsetof(VexGuestPPC64State,guest_GPR2);
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    offB_LR   = offsetof(VexGuestPPC64State,guest_LR);
1149663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   Int    offB_CIA  = offsetof(VexGuestPPC64State,guest_CIA);
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_R2    = newIRTemp( bb->tyenv, Ity_I64 );
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp old_LR    = newIRTemp( bb->tyenv, Ity_I64 );
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Restore R2 */
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_R2 = gen_POP( bb );
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_GPR2, IRExpr_RdTmp(old_R2)) );
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Restore LR */
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old_LR = gen_POP( bb );
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( bb, IRStmt_Put( offB_LR, IRExpr_RdTmp(old_LR)) );
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Branch to LR */
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* re boring, we arrived here precisely because a wrapped fn did a
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      blr (hence Ijk_Ret); so we should just mark this jump as Boring,
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else one _Call will have resulted in two _Rets. */
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bb->jumpkind = Ijk_Boring;
1163663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->next     = IRExpr_Binop(Iop_And64, IRExpr_RdTmp(old_LR), mkU64(~(3ULL)));
1164663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   bb->offsIP   = offB_CIA;
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Platform is not TOC-afflicted, fortunately
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__ppctoc_magic_return_stub ( void* closureV, IRSB* bb )
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Since we're creating the entire IRSB right here, give it a
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      proper IMark, as it won't get one any other way, and cachegrind
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      will barf if it doesn't have one (fair enough really). */
1177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   addStmtToIRSB( bb, IRStmt_IMark( closure->readdr, 4, 0 ) );
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Generate the magic sequence:
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pop R2 from hidden stack
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pop LR from hidden stack
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto LR
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_pop_R2_LR_then_bLR(bb);
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True; /* True == this is the entire BB; don't disassemble any
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   real insns into it - just hand it directly to
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   optimiser/instrumenter/backend. */
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- END helpers for with-TOC platforms --------------- */
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the IR preamble generator used for replacement
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   functions.  It adds code to set the guest_NRADDR{_GPR2} to zero
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (technically not necessary, but facilitates detecting mixups in
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which a replacement function has been erroneously declared using
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_REPLACE_FUNCTION_Z{U,Z} when instead it should have been written
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   using VG_WRAP_FUNCTION_Z{U,Z}).
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   On with-TOC platforms the follow hacks are also done: LR and R2 are
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   pushed onto a hidden stack, R2 is set to the correct value for the
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   replacement function, and LR is set to point at the magic
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return-stub address.  Setting LR causes the return of the
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wrapped/redirected function to lead to our magic return stub, which
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restores LR and R2 from said stack and returns for real.
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(get_StackTrace_wrk) understands that the LR value may point to
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the return stub address, and that in that case it can get the real
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LR value from the hidden stack instead. */
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__set_NRADDR_to_zero ( void* closureV, IRSB* bb )
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int nraddr_szB
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == VG_WORDSIZE);
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR),
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nraddr_szB == 8 ? mkU64(0) : mkU32(0)
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1224663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // t9 needs to be set to point to the start of the redirected function.
1225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGP_mips32_linux)
1226663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1227436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int offB_GPR25 = offsetof(VexGuestMIPS32State, guest_r25);
1228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   addStmtToIRSB(bb, IRStmt_Put(offB_GPR25, mkU32(closure->readdr)));
1229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  endif
1230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGP_mips64_linux)
1231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int offB_GPR25 = offsetof(VexGuestMIPS64State, guest_r25);
1233436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   addStmtToIRSB(bb, IRStmt_Put(offB_GPR25, mkU64(closure->readdr)));
1234663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     addStmtToIRSB(
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        bb,
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRStmt_Put(
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           VG_WORDSIZE==8 ? mkU64(0) : mkU32(0)
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Ditto, except set guest_NRADDR to nraddr (the un-redirected guest
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   address).  This is needed for function wrapping - so the wrapper
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   can read _NRADDR and find the address of the function being
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wrapped.  On toc-afflicted platforms we must also snarf r2. */
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool mk_preamble__set_NRADDR_to_nraddr ( void* closureV, IRSB* bb )
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure* closure = (VgCallbackClosure*)closureV;
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int nraddr_szB
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = sizeof(((VexGuestArchState*)0)->guest_NRADDR);
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == 4 || nraddr_szB == 8);
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(nraddr_szB == VG_WORDSIZE);
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR),
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nraddr_szB == 8
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ? IRExpr_Const(IRConst_U64( closure->nraddr ))
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            : IRExpr_Const(IRConst_U32( (UInt)closure->nraddr ))
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1271663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   // t9 needs to be set to point to the start of the redirected function.
1272436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGP_mips32_linux)
1273436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int offB_GPR25 = offsetof(VexGuestMIPS32State, guest_r25);
1274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   addStmtToIRSB(bb, IRStmt_Put(offB_GPR25, mkU32(closure->readdr)));
1275436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  endif
1276436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  if defined(VGP_mips64_linux)
1277436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Int offB_GPR25 = offsetof(VexGuestMIPS64State, guest_r25);
1278436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   addStmtToIRSB(bb, IRStmt_Put(offB_GPR25, mkU64(closure->readdr)));
1279663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  endif
1280b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGP_ppc64_linux)
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB(
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bb,
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Put(
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         offsetof(VexGuestArchState,guest_NRADDR_GPR2),
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr_Get(offsetof(VexGuestArchState,guest_GPR2),
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    VG_WORDSIZE==8 ? Ity_I64 : Ity_I32)
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gen_push_and_set_LR_R2 ( bb, VG_(get_tocptr)( closure->readdr ) );
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Helpers to do with PPC related stack redzones. --- */
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__((unused))
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool const_True ( Addr64 guest_addr )
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------------- main translation function --------------- */
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Note: see comments at top of m_redir.c for the Big Picture on how
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   redirections are managed. */
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* normal translation, redir neither requested nor inhibited */
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Normal,
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* redir translation, function-wrap (set _NRADDR) style */
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Redir_Wrap,
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* redir translation, replacement (don't set _NRADDR) style */
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_Redir_Replace,
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* a translation in which redir is specifically disallowed */
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      T_NoRedir
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   T_Kind;
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translate the basic block beginning at NRADDR, and add it to the
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translation cache & translation table.  Unless
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DEBUGGING_TRANSLATION is true, in which case the call is being done
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for debugging purposes, so (a) throw away the translation once it
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is made, and (b) produce a load of debugging output.  If
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ALLOW_REDIRECTION is False, do not attempt redirection of NRADDR,
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and also, put the resulting translation into the no-redirect tt/tc
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instead of the normal one.
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TID is the identity of the thread requesting this translation.
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool VG_(translate) ( ThreadId tid,
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Addr64   nraddr,
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool     debugging_translation,
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Int      debugging_verbosity,
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      ULong    bbs_done,
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool     allow_redirection )
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Addr64             addr;
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   T_Kind             kind;
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int                tmpbuf_used, verbosity, i;
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool (*preamble_fn)(void*,IRSB*);
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexArch            vex_arch;
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexArchInfo        vex_archinfo;
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexAbiInfo         vex_abiinfo;
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestExtents    vge;
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexTranslateArgs   vta;
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexTranslateResult tres;
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VgCallbackClosure  closure;
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure Vex is initialised right. */
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Bool vex_init_done = False;
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!vex_init_done) {
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_Init ( &failure_exit, &log_bytes,
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    1,     /* debug_paranoia */
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    False, /* valgrind support */
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &VG_(clo_vex_control) );
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_init_done = True;
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Establish the translation kind and actual guest address to
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start from.  Sets (addr,kind). */
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (allow_redirection) {
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isWrap;
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr64 tmp = VG_(redir_do_lookup)( nraddr, &isWrap );
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (tmp == nraddr) {
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* no redirection found */
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = nraddr;
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kind = T_Normal;
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* found a redirect */
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = tmp;
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kind = isWrap ? T_Redir_Wrap : T_Redir_Replace;
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = nraddr;
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kind = T_NoRedir;
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Established: (nraddr, addr, kind) */
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Printing redirection info. */
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((kind == T_Redir_Wrap || kind == T_Redir_Replace)
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (VG_(clo_verbosity) >= 2 || VG_(clo_trace_redir))) {
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok;
1389436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar name1[512] = "";
1390436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar name2[512] = "";
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      name1[0] = name2[0] = 0;
1392663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ok = VG_(get_fnname_w_offset)(nraddr, name1, 512);
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok) VG_(strcpy)(name1, "???");
1394663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      ok = VG_(get_fnname_w_offset)(addr, name2, 512);
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok) VG_(strcpy)(name2, "???");
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_DebugMsg,
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   "REDIR: 0x%llx (%s) redirected to 0x%llx (%s)\n",
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nraddr, name1,
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   addr, name2 );
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!debugging_translation)
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( pre_mem_read, Vg_CoreTranslate,
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              tid, "(translator)", addr, 1 );
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If doing any code printing, print a basic block start marker */
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_flags) || debugging_translation) {
1408436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      HChar fnname[512] = "UNKNOWN_FUNCTION";
1409663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      VG_(get_fnname_w_offset)(addr, fnname, 512);
1410436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* objname = "UNKNOWN_OBJECT";
1411b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      OffT         objoff  = 0;
1412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DebugInfo*   di      = VG_(find_DebugInfo)( addr );
1413b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (di) {
1414b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         objname = VG_(DebugInfo_get_filename)(di);
1415b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         objoff  = addr - VG_(DebugInfo_get_text_bias)(di);
1416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
1417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(objname);
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf)(
1419663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         "==== SB %d (evchecks %lld) [tid %d] 0x%llx %s %s+0x%llx\n",
1420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(get_bbs_translated)(), bbs_done, (Int)tid, addr,
1421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         fnname, objname, (ULong)objoff
1422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      );
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Are we allowed to translate here? */
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { /* BEGIN new scope specially for 'seg' */
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NSegment const* seg = VG_(am_find_nsegment)(addr);
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1430436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if ( (!translations_allowable_from_seg(seg, addr))
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        || addr == TRANSTAB_BOGUS_GUEST_ADDR ) {
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg, "translations not allowed here (0x%llx)"
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   " - throwing SEGV\n", addr);
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* U R busted, sonny.  Place your hands on your head and step
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         away from the orig_addr. */
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Code address is bad - deliver a signal instead */
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (seg != NULL) {
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* There's some kind of segment at the requested place, but we
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            aren't allowed to execute code here. */
1441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (debugging_translation)
1442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("translations not allowed here (segment not executable)"
1443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        "(0x%llx)\n", addr);
1444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1445b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(synth_fault_perms)(tid, addr);
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        /* There is no segment at all; we are attempting to execute in
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           the middle of nowhere. */
1449b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (debugging_translation)
1450b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(printf)("translations not allowed here (no segment)"
1451b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        "(0x%llx)\n", addr);
1452b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         else
1453b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(synth_fault_mapping)(tid, addr);
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* True if a debug trans., or if bit N set in VG_(clo_trace_codegen). */
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   verbosity = 0;
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (debugging_translation) {
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      verbosity = debugging_verbosity;
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (VG_(clo_trace_flags) > 0
1465663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        && VG_(get_bbs_translated)() <= VG_(clo_trace_notabove)
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && VG_(get_bbs_translated)() >= VG_(clo_trace_notbelow) )) {
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      verbosity = VG_(clo_trace_flags);
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out which preamble-mangling callback to send. */
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   preamble_fn = NULL;
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (kind == T_Redir_Replace)
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__set_NRADDR_to_zero;
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (kind == T_Redir_Wrap)
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__set_NRADDR_to_nraddr;
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VG_PLAT_USES_PPCTOC)
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ULong_to_Ptr(nraddr)
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       == (void*)&VG_(ppctoc_magic_redirect_return_stub)) {
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* If entering the special return stub, this means a wrapped or
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         redirected function is returning.  Make this translation one
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         which restores R2 and LR from the thread's hidden redir
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stack, and branch to the (restored) link register, thereby
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         really causing the function to return. */
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(kind == T_Normal);
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(nraddr == addr);
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      preamble_fn = mk_preamble__ppctoc_magic_return_stub;
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ Actually do the translation. ------ */
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert2(VG_(tdict).tool_instrument,
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              "you forgot to set VgToolInterface function 'tool_instrument'");
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the CPU info established at startup. */
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up 'abiinfo' structure with stuff Vex needs to know about
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the guest and host ABIs. */
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LibVEX_default_VexAbiInfo( &vex_abiinfo );
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_stack_redzone_size = VG_STACK_REDZONE_SZB;
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_amd64_linux)
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_amd64_assume_fs_is_zero  = True;
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_amd64_darwin)
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_amd64_assume_gs_is_0x60  = True;
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc32_linux)
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_blr        = False;
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_bl         = NULL;
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.host_ppc32_regalign_int64_args = True;
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_ppc64_linux)
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_blr        = True;
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.guest_ppc_zap_RZ_at_bl         = const_True;
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_abiinfo.host_ppc_calls_use_fndescrs    = True;
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up closure args. */
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.tid    = tid;
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.nraddr = nraddr;
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   closure.readdr = addr;
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up args for LibVEX_Translate. */
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.arch_guest       = vex_arch;
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.archinfo_guest   = vex_archinfo;
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.arch_host        = vex_arch;
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.archinfo_host    = vex_archinfo;
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.abiinfo_both     = vex_abiinfo;
1533663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.callback_opaque  = (void*)&closure;
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_bytes      = (UChar*)ULong_to_Ptr(addr);
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_bytes_addr = (Addr64)addr;
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.chase_into_ok    = chase_into_ok;
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.guest_extents    = &vge;
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes       = tmpbuf;
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes_size  = N_TMPBUF;
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vta.host_bytes_used  = &tmpbuf_used;
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { /* At this point we have to reconcile Vex's view of the
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        instrumentation callback - which takes a void* first argument
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        - with Valgrind's view, in which the first arg is a
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        VgCallbackClosure*.  Hence the following longwinded casts.
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        They are entirely legal but longwinded so as to maximise the
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        chance of the C typechecker picking up any type snafus. */
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRSB*(*f)(VgCallbackClosure*,
1548436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               IRSB*,VexGuestLayout*,VexGuestExtents*, VexArchInfo*,
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRType,IRType)
1550b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        = VG_(clo_vgdb) != Vg_VgdbNo
1551b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             ? tool_instrument_then_gdbserver_if_needed
1552b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             : VG_(tdict).tool_instrument;
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRSB*(*g)(void*,
1554436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov               IRSB*,VexGuestLayout*,VexGuestExtents*,VexArchInfo*,
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRType,IRType)
1556436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov       = (IRSB*(*)(void*,IRSB*,VexGuestLayout*,VexGuestExtents*,
1557436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                   VexArchInfo*,IRType,IRType))f;
1558663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     vta.instrument1     = g;
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* No need for type kludgery here. */
1561663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.instrument2       = need_to_handle_SP_assignment()
1562663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              ? vg_SP_update_pass
1563663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              : NULL;
1564663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.finaltidy         = VG_(needs).final_IR_tidy_pass
1565663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              ? VG_(tdict).tool_final_IR_tidy_pass
1566663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                              : NULL;
1567663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.needs_self_check  = needs_self_check;
1568663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.preamble_function = preamble_fn;
1569663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.traceflags        = verbosity;
1570436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vta.sigill_diag       = VG_(clo_sigill_diag);
1571436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vta.addProfInc        = VG_(clo_profyle_sbs) && kind != T_NoRedir;
1572663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1573663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Set up the dispatch continuation-point info.  If this is a
1574663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      no-redir translation then it cannot be chained, and the chain-me
1575663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      points are set to NULL to indicate that.  The indir point must
1576663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      also be NULL, since we can't allow this translation to do an
1577663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      indir transfer -- that would take it back into the main
1578663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      translation cache too.
1579663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1580663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      All this is because no-redir translations live outside the main
1581663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      translation cache (in a secondary one) and chaining them would
1582663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      involve more adminstrative complexity that isn't worth the
1583663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      hassle, because we don't expect them to get used often.  So
1584663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      don't bother. */
1585663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (allow_redirection) {
1586663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_slowEP
1587663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_slowEP) );
1588663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_fastEP
1589663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_chain_me_to_fastEP) );
1590663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_xindir
1591663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xindir) );
1592663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
1593663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_slowEP = NULL;
1594663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_chain_me_to_fastEP = NULL;
1595663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vta.disp_cp_xindir             = NULL;
1596b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1597663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* This doesn't involve chaining and so is always allowable. */
1598663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vta.disp_cp_xassisted
1599663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      = VG_(fnptr_to_fnentry)( &VG_(disp_cp_xassisted) );
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Sheesh.  Finally, actually _do_ the translation! */
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tres = LibVEX_Translate ( &vta );
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1604b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(tres.status == VexTransOK);
1605b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(tres.n_sc_extents >= 0 && tres.n_sc_extents <= 3);
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used <= N_TMPBUF);
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used > 0);
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell aspacem of all segments that have had translations taken
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from them.  Optimisation: don't re-look up vge.base[0] since seg
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      should already point to it. */
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert( vge.base[0] == (Addr64)addr );
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* set 'translations taken from this segment' flag */
1615436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( seg );
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* END new scope specially for 'seg' */
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 1; i < vge.n_used; i++) {
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NSegment const* seg
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = VG_(am_find_nsegment)( vge.base[i] );
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set 'translations taken from this segment' flag */
1622436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(am_set_segment_hasT_if_SkFileC_or_SkAnonC)( seg );
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy data at trans_addr into the translation cache. */
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // If debugging, don't do anything with the translated block;  we
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // only did this for the debugging output produced along the way.
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!debugging_translation) {
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (kind != T_NoRedir) {
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // Put it into the normal TT/TC structures.  This is the
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // normal case.
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // Note that we use nraddr (the non-redirected address), not
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          // addr, which might have been changed by the redirection
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          VG_(add_to_transtab)( &vge,
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nraddr,
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                (Addr)(&tmpbuf[0]),
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                tmpbuf_used,
1642663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.n_sc_extents > 0,
1643663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.offs_profInc,
1644663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                tres.n_guest_instrs,
1645663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                                vex_arch );
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1647663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng          vg_assert(tres.offs_profInc == -1); /* -1 == unset */
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          VG_(add_to_unredir_transtab)( &vge,
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        nraddr,
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        (Addr)(&tmpbuf[0]),
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        tmpbuf_used );
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1661