blob: fb38a2ea2ac86fe0c6789388efdb8bd8f87fdf5c [file] [log] [blame]
/*---------------------------------------------------------------*/
/*--- ---*/
/*--- This file (guest-ppc32/ghelpers.c) is ---*/
/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
/*--- ---*/
/*---------------------------------------------------------------*/
/*
This file is part of LibVEX, a library for dynamic binary
instrumentation and translation.
Copyright (C) 2004 OpenWorks, LLP.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; Version 2 dated June 1991 of the
license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
for damages. See the GNU General Public License for more details.
Neither the names of the U.S. Department of Energy nor the
University of California nor the names of its contributors may be
used to endorse or promote products derived from this software
without prior written permission.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
*/
#include "libvex_basictypes.h"
#include "libvex_emwarn.h"
#include "libvex_guest_ppc32.h"
#include "libvex_ir.h"
#include "libvex.h"
#include "main/vex_util.h"
#include "guest-ppc32/gdefs.h"
/* This file contains helper functions for ppc32 guest code.
Calls to these functions are generated by the back end.
These calls are of course in the host machine code and
this file will be compiled to host machine code, so that
all makes sense.
Only change the signatures of these helper functions very
carefully. If you change the signature here, you'll have to change
the parameters passed to it in the IR calls constructed by
guest-ppc32/toIR.c.
*/
#define INT32_MIN (-2147483647-1)
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
/* Calculates CR7[LT,GT,EQ,SO] flags from the supplied
thunk parameters.
Returns values in high field (correct wrt actual CR)
*/
UInt ppc32g_calculate_cr7 ( UInt op, UInt val, UInt xer_so )
{
if (op) { // val contains cr7 flags to be returned
return (val & 0xF0000000);
} else { // val contains result to be tested
Int sval = (Int)val;
xer_so = xer_so & 1;
return ( ((xer_so == 1) ? (1<<28) : 0)
| ((sval == 0) ? (1<<29) : 0)
| ((sval > 0) ? (1<<30) : 0)
| ((sval < 0) ? (1<<31) : 0) );
}
}
// Calculate XER_OV
UInt ppc32g_calculate_xer_ov ( UInt op, UInt res, UInt argL, UInt argR )
{
switch (op) {
case PPC32G_FLAG_OP_ADD: // addo, addc
case PPC32G_FLAG_OP_ADDE: // addeo, addmeo, addzeo
return ((argL^argR^-1) & (argL^res) & (1<<31)) ? 1:0;
// i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
case PPC32G_FLAG_OP_DIVW: // divwo
return ((argL == INT32_MIN && argR == -1) || argR == 0) ? 1:0;
case PPC32G_FLAG_OP_DIVWU: // divwuo
return (argR == 0) ? 1:0;
case PPC32G_FLAG_OP_MULLW: { // mullwo
/* OV true if result can't be represented in 32 bits
i.e sHi != sign extension of sLo */
Long l_res = (Long)((Int)argL) * (Long)((Int)argR);
Int sHi = (Int)(l_res >> 32);
Int sLo = (Int)l_res;
return (sHi != (sLo >> /*s*/ 31)) ? 1:0;
}
case PPC32G_FLAG_OP_NEG: // nego
return (argL == 0x80000000) ? 1:0;
case PPC32G_FLAG_OP_SUBF: // subfo
case PPC32G_FLAG_OP_SUBFC: // subfco
case PPC32G_FLAG_OP_SUBFE: // subfeo, subfmeo, subfzeo
return (((~argL)^argR^(-1)) & ((~argL)^res) & (1<<31)) ? 1:0;
default:
break;
}
vpanic("ppc32g_calculate_xer_ov(ppc32)");
return 0; // notreached
}
// Calculate XER_CA
UInt ppc32g_calculate_xer_ca ( UInt op, UInt res,
UInt argL, UInt argR, UInt ca )
{
switch (op) {
case PPC32G_FLAG_OP_ADD: // addc[o], addic
return (res < argL) ? 1:0;
case PPC32G_FLAG_OP_ADDE: // adde[o], addze[o], addme[o]
return (res < argL || (ca==1 && res==argL)) ? 1:0;
case PPC32G_FLAG_OP_SUBFC: // subfc[o]
case PPC32G_FLAG_OP_SUBFI: // subfic
return (res <= argR) ? 1:0;
case PPC32G_FLAG_OP_SUBFE: // subfe[o], subfze[o], subfme[o]
return ((res < argR) || (ca == 1 && res == argR)) ? 1:0;
case PPC32G_FLAG_OP_SRAW: // sraw
if ((argR & 0x20) == 0) { // shift <= 31
// xer_ca = sign && (bits_shifted_out != 0)
return (((argL & 0x80000000) &&
((argL & (0xFFFFFFFF >> (32-argR))) != 0)) != 0) ? 1:0;
}
// shift > 31
// xer_ca = sign && src != 0
return (((argL & 0x80000000) && (argR != 0)) != 0) ? 1:0;
case PPC32G_FLAG_OP_SRAWI: // srawi
// xer_ca = sign && (bits_shifted_out != 0)
return (((argL & 0x80000000) &&
((argL & (0xFFFFFFFF >> (32-argR))) != 0)) != 0) ? 1:0;
default:
break;
}
vpanic("ppc32g_calculate_xer_ov(ppc32)");
return 0; // notreached
}
/* Used by the optimiser to try specialisations. Returns an
equivalent expression, or NULL if none. */
#if 0
/* temporarily unused */
static Bool isU32 ( IRExpr* e, UInt n )
{
return (e->tag == Iex_Const
&& e->Iex.Const.con->tag == Ico_U32
&& e->Iex.Const.con->Ico.U32 == n);
}
#endif
IRExpr* guest_ppc32_spechelper ( HChar* function_name,
IRExpr** args )
{
return NULL;
}
/*----------------------------------------------*/
/*--- The exported fns .. ---*/
/*----------------------------------------------*/
/* VISIBLE TO LIBVEX CLIENT */
#if 0
void LibVEX_GuestPPC32_put_cr7 ( UInt flags_native,
/*OUT*/VexGuestPPC32State* vex_state )
{
vassert(0); // FIXME
}
#endif
/* VISIBLE TO LIBVEX CLIENT */
UInt LibVEX_GuestPPC32_get_cr7 ( /*IN*/VexGuestPPC32State* vex_state )
{
UInt flags = ppc32g_calculate_cr7(
vex_state->guest_CC_OP,
vex_state->guest_CC_DEP1,
vex_state->guest_CC_DEP2
);
return flags;
}
/* VISIBLE TO LIBVEX CLIENT */
void LibVEX_GuestPPC32_initialise ( /*OUT*/VexGuestPPC32State* vex_state )
{
vex_state->guest_GPR0 = 0;
vex_state->guest_GPR1 = 0;
vex_state->guest_GPR2 = 0;
vex_state->guest_GPR3 = 0;
vex_state->guest_GPR4 = 0;
vex_state->guest_GPR5 = 0;
vex_state->guest_GPR6 = 0;
vex_state->guest_GPR7 = 0;
vex_state->guest_GPR8 = 0;
vex_state->guest_GPR9 = 0;
vex_state->guest_GPR10 = 0;
vex_state->guest_GPR11 = 0;
vex_state->guest_GPR12 = 0;
vex_state->guest_GPR13 = 0;
vex_state->guest_GPR14 = 0;
vex_state->guest_GPR15 = 0;
vex_state->guest_GPR16 = 0;
vex_state->guest_GPR17 = 0;
vex_state->guest_GPR18 = 0;
vex_state->guest_GPR19 = 0;
vex_state->guest_GPR20 = 0;
vex_state->guest_GPR21 = 0;
vex_state->guest_GPR22 = 0;
vex_state->guest_GPR23 = 0;
vex_state->guest_GPR24 = 0;
vex_state->guest_GPR25 = 0;
vex_state->guest_GPR26 = 0;
vex_state->guest_GPR27 = 0;
vex_state->guest_GPR28 = 0;
vex_state->guest_GPR29 = 0;
vex_state->guest_GPR30 = 0;
vex_state->guest_GPR31 = 0;
vex_state->guest_CIA = 0;
vex_state->guest_LR = 0;
vex_state->guest_CTR = 0;
vex_state->guest_CC_OP = 0;
vex_state->guest_CC_DEP1 = 0;
vex_state->guest_CC_DEP2 = 0;
vex_state->guest_CR0to6 = 0;
vex_state->guest_FPROUND = (UInt)PPC32rm_NEAREST;
vex_state->guest_XER = 0;
vex_state->guest_EMWARN = EmWarn_NONE;
vex_state->guest_TISTART = 0;
vex_state->guest_TILEN = 0;
}
/*-----------------------------------------------------------*/
/*--- Describing the ppc32 guest state, for the benefit ---*/
/*--- of iropt and instrumenters. ---*/
/*-----------------------------------------------------------*/
/* Figure out if any part of the guest state contained in minoff
.. maxoff requires precise memory exceptions. If in doubt return
True (but this is generates significantly slower code).
By default we enforce precise exns for guest R1 (stack pointer),
CIA (current insn address) and LR (link register). These are the
minimum needed to extract correct stack backtraces from ppc32
code. [[NB: not sure if keeping LR up to date is actually
necessary.]]
*/
Bool guest_ppc32_state_requires_precise_mem_exns ( Int minoff,
Int maxoff )
{
Int lr_min = offsetof(VexGuestPPC32State, guest_LR);
Int lr_max = lr_min + 4 - 1;
Int r1_min = offsetof(VexGuestPPC32State, guest_GPR1);
Int r1_max = r1_min + 4 - 1;
Int cia_min = offsetof(VexGuestPPC32State, guest_CIA);
Int cia_max = cia_min + 4 - 1;
if (maxoff < lr_min || minoff > lr_max) {
/* no overlap with LR */
} else {
return True;
}
if (maxoff < r1_min || minoff > r1_max) {
/* no overlap with R1 */
} else {
return True;
}
if (maxoff < cia_min || minoff > cia_max) {
/* no overlap with CIA */
} else {
return True;
}
return False;
}
#define ALWAYSDEFD(field) \
{ offsetof(VexGuestPPC32State, field), \
(sizeof ((VexGuestPPC32State*)0)->field) }
VexGuestLayout
ppc32Guest_layout
= {
/* Total size of the guest state, in bytes. */
.total_sizeB = sizeof(VexGuestPPC32State),
/* Describe the stack pointer. */
.offset_SP = offsetof(VexGuestPPC32State,guest_GPR1),
.sizeof_SP = 4,
/* Describe the instruction pointer. */
.offset_IP = offsetof(VexGuestPPC32State,guest_CIA),
.sizeof_IP = 4,
/* Describe any sections to be regarded by Memcheck as
'always-defined'. */
.n_alwaysDefd = 1,
/* flags thunk: only using last_result, which is always defd. */
.alwaysDefd
= { /* 0 */ ALWAYSDEFD(guest_CC_OP)
// FIXME
}
};
/*---------------------------------------------------------------*/
/*--- end guest-ppc32/ghelpers.c ---*/
/*---------------------------------------------------------------*/