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