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