| |
| /*---------------------------------------------------------------*/ |
| /*--- ---*/ |
| /*--- This file (guest-arm/ghelpers.c) is ---*/ |
| /*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/ |
| /*--- ---*/ |
| /*---------------------------------------------------------------*/ |
| |
| /* |
| This file is part of LibVEX, a library for dynamic binary |
| instrumentation and translation. |
| |
| Copyright (C) 2004-2006 OpenWorks LLP. All rights reserved. |
| |
| This library is made available under a dual licensing scheme. |
| |
| If you link LibVEX against other code all of which is itself |
| licensed under the GNU General Public License, version 2 dated June |
| 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL |
| v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL |
| is missing, you can obtain a copy of the GPL v2 from the Free |
| Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA |
| 02110-1301, USA. |
| |
| For any other uses of LibVEX, you must first obtain a commercial |
| license from OpenWorks LLP. Please contact info@open-works.co.uk |
| for information about commercial licensing. |
| |
| This software is provided by OpenWorks LLP "as is" and any express |
| or implied warranties, including, but not limited to, the implied |
| warranties of merchantability and fitness for a particular purpose |
| are disclaimed. In no event shall OpenWorks LLP be liable for any |
| direct, indirect, incidental, special, exemplary, or consequential |
| damages (including, but not limited to, procurement of substitute |
| goods or services; loss of use, data, or profits; or business |
| interruption) however caused and on any theory of liability, |
| whether in contract, strict liability, or tort (including |
| negligence or otherwise) arising in any way out of the use of this |
| software, even if advised of the possibility of such damage. |
| |
| 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. |
| */ |
| |
| #include "libvex_basictypes.h" |
| #include "libvex_guest_arm.h" |
| #include "libvex_ir.h" |
| #include "libvex.h" |
| |
| #include "main/vex_util.h" |
| #include "guest-arm/gdefs.h" |
| |
| |
| /* This file contains helper functions for arm 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-arm/toIR.c. |
| */ |
| |
| |
| |
| |
| |
| |
| |
| #define BORROWFROM() \ |
| { \ |
| } |
| #define OVERFLOWFROM() \ |
| { \ |
| } |
| |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| LOGIC: EOR, AND, TST, TEQ, MOV, ORR, MVN, BIC |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: shifter_carry_out |
| v: unaffected |
| */ |
| #define ACTIONS_LOGIC() \ |
| { \ |
| { Int nf, zf, cf, vf; \ |
| Int oldV=0; /* CAB: vf unaffected: what todo? */ \ |
| nf = cc_dep1_formal & ARMG_CC_MASK_N; \ |
| zf = cc_dep1_formal == 0 ? 1 : 0; \ |
| cf = (cc_dep2_formal << ARMG_CC_SHIFT_C) & ARMG_CC_MASK_C; \ |
| vf = oldV & ARMG_CC_MASK_V; \ |
| return nf | zf | cf | vf; \ |
| } \ |
| } |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| ADD: ADD, CMN |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: CarryFrom(Rn + shifter_op) |
| v: OverflowFrom(Rn + shifter_op) |
| */ |
| #define ACTIONS_ADD() \ |
| { \ |
| { Int nf, zf, cf, vf; \ |
| Int argL, argR, res; \ |
| argL = cc_dep1_formal; \ |
| argR = cc_dep2_formal; \ |
| res = argL + argR; \ |
| nf = res & ARMG_CC_MASK_N; \ |
| zf = (res == 0) << ARMG_CC_SHIFT_Z; \ |
| cf = ((UInt)argL < (UInt)argR) << ARMG_CC_SHIFT_C; \ |
| vf = (((argL ^ argR ^ -1) & (argL ^ res)) >> \ |
| (32 - ARMG_CC_SHIFT_V)) & ARMG_CC_MASK_V; \ |
| return nf | zf | cf | vf; \ |
| } \ |
| } |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| SUB: SUB, CMP, RSB |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: NOT BorrowFrom(Rn - shifter_op) |
| v: OverflowFrom(Rn - shifter_op) |
| */ |
| // CAB: cf right? ARM ARM A4-99 |
| #define ACTIONS_SUB() \ |
| { \ |
| { Int nf, zf, cf, vf; \ |
| Int argL, argR, res; \ |
| argL = cc_dep1_formal; \ |
| argR = cc_dep2_formal; \ |
| res = argL - argR; \ |
| nf = res & ARMG_CC_MASK_N; \ |
| zf = (res == 0) << ARMG_CC_SHIFT_Z; \ |
| cf = (~((UInt)argL < (UInt)argR) << \ |
| ARMG_CC_SHIFT_C) & ARMG_CC_MASK_C; \ |
| vf = (((argL ^ argR ^ -1) & (argL ^ res)) >> \ |
| (32 - ARMG_CC_SHIFT_V)) & ARMG_CC_MASK_V; \ |
| return nf | zf | cf | vf; \ |
| } \ |
| } |
| |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| ADC |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: CarryFrom(Rn + shifter_op + C Flag) |
| v: OverflowFrom(Rn + shifter_op + C Flag) |
| */ |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| RSC |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: NOT BorrowFrom(shifter_op - Rn - NOT(C Flag)) |
| v: OverflowFrom(shifter_op - Rn - NOT(C Flag)) |
| */ |
| |
| /*-------------------------------------------------------------*/ |
| /* |
| SBC |
| ---------------- |
| n: Rd[31] |
| z: Rd==0 ? 1:0 |
| c: NOT BorrowFrom(Rn - shifter_op - NOT(C Flag)) |
| v: OverflowFrom(Rn - shifter_op - NOT(C Flag)) |
| */ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| /* CALLED FROM GENERATED CODE: CLEAN HELPER */ |
| /* Calculate all the 4 flags from the supplied thunk parameters. */ |
| UInt armg_calculate_flags_all ( UInt cc_op, |
| UInt cc_dep1_formal, |
| UInt cc_dep2_formal ) |
| { |
| switch (cc_op) { |
| case ARMG_CC_OP_LOGIC: ACTIONS_LOGIC(); |
| case ARMG_CC_OP_ADD: ACTIONS_ADD(); |
| case ARMG_CC_OP_SUB: ACTIONS_SUB(); |
| |
| default: |
| /* shouldn't really make these calls from generated code */ |
| vex_printf("armg_calculate_flags_all(ARM)( %u, 0x%x, 0x%x )\n", |
| cc_op, cc_dep1_formal, cc_dep2_formal ); |
| vpanic("armg_calculate_flags_all(ARM)"); |
| } |
| } |
| |
| /* CALLED FROM GENERATED CODE: CLEAN HELPER */ |
| /* Calculate just the carry flag from the supplied thunk parameters. */ |
| UInt armg_calculate_flags_c ( UInt cc_op, |
| UInt cc_dep1, |
| UInt cc_dep2 ) |
| { |
| /* Fast-case some common ones. */ |
| switch (cc_op) { |
| default: |
| break; |
| } |
| return armg_calculate_flags_all(cc_op,cc_dep1,cc_dep2) & ARMG_CC_MASK_C; |
| } |
| |
| |
| |
| /* CALLED FROM GENERATED CODE: CLEAN HELPER */ |
| /* returns 1 or 0 */ |
| /*static*/ |
| UInt armg_calculate_condition ( UInt/*ARMCondcode*/ cond, |
| UInt cc_op, |
| UInt cc_dep1, |
| UInt cc_dep2 ) |
| { |
| UInt nf,zf,vf,cf; |
| UInt inv = cond & 1; |
| |
| UInt nzvc = armg_calculate_flags_all(cc_op, cc_dep1, cc_dep2); |
| |
| switch (cond) { |
| case ARMCondEQ: // Z=1 => z |
| case ARMCondNE: // Z=0 |
| zf = nzvc >> ARMG_CC_SHIFT_Z; |
| return 1 & (inv ^ zf); |
| |
| case ARMCondHS: // C=1 => c |
| case ARMCondLO: // C=0 |
| cf = nzvc >> ARMG_CC_SHIFT_C; |
| return 1 & (inv ^ cf); |
| |
| case ARMCondMI: // N=1 => n |
| case ARMCondPL: // N=0 |
| nf = nzvc >> ARMG_CC_SHIFT_N; |
| return 1 & (inv ^ nf); |
| |
| case ARMCondVS: // V=1 => v |
| case ARMCondVC: // V=0 |
| vf = nzvc >> ARMG_CC_SHIFT_V; |
| return 1 & (inv ^ vf); |
| |
| case ARMCondHI: // C=1 && Z=0 => c & ~z |
| case ARMCondLS: // C=0 || Z=1 |
| cf = nzvc >> ARMG_CC_SHIFT_C; |
| zf = nzvc >> ARMG_CC_SHIFT_Z; |
| return 1 & (inv ^ (cf & ~zf)); |
| |
| case ARMCondGE: // N=V => ~(n^v) |
| case ARMCondLT: // N!=V |
| nf = nzvc >> ARMG_CC_SHIFT_N; |
| vf = nzvc >> ARMG_CC_SHIFT_V; |
| return 1 & (inv ^ ~(nf ^ vf)); |
| |
| case ARMCondGT: // Z=0 && N=V => (~z & ~(n^v) => ~(z | (n^v) |
| case ARMCondLE: // Z=1 || N!=V |
| nf = nzvc >> ARMG_CC_SHIFT_N; |
| vf = nzvc >> ARMG_CC_SHIFT_V; |
| zf = nzvc >> ARMG_CC_SHIFT_Z; |
| return 1 & (inv ^ ~(zf | (nf ^ vf))); |
| |
| case ARMCondAL: // should never get here: Always => no flags to calc |
| case ARMCondNV: // should never get here: Illegal instr |
| default: |
| /* shouldn't really make these calls from generated code */ |
| vex_printf("armg_calculate_condition(ARM)( %u, %u, 0x%x, 0x%x )\n", |
| cond, cc_op, cc_dep1, cc_dep2 ); |
| vpanic("armg_calculate_condition(ARM)"); |
| } |
| } |
| |
| |
| /* 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_arm_spechelper ( HChar* function_name, |
| IRExpr** args ) |
| { |
| return NULL; |
| } |
| |
| |
| /*----------------------------------------------*/ |
| /*--- The exported fns .. ---*/ |
| /*----------------------------------------------*/ |
| |
| /* VISIBLE TO LIBVEX CLIENT */ |
| #if 0 |
| void LibVEX_GuestARM_put_flags ( UInt flags_native, |
| /*OUT*/VexGuestARMState* vex_state ) |
| { |
| vassert(0); // FIXME |
| |
| /* Mask out everything except N Z V C. */ |
| flags_native |
| &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z | ARMG_CC_MASK_V | ARMG_CC_MASK_C); |
| |
| vex_state->guest_CC_OP = ARMG_CC_OP_COPY; |
| vex_state->guest_CC_DEP1 = flags_native; |
| vex_state->guest_CC_DEP2 = 0; |
| } |
| #endif |
| |
| /* VISIBLE TO LIBVEX CLIENT */ |
| UInt LibVEX_GuestARM_get_flags ( /*IN*/VexGuestARMState* vex_state ) |
| { |
| UInt flags; |
| vassert(0); // FIXME |
| |
| flags = armg_calculate_flags_all( |
| vex_state->guest_CC_OP, |
| vex_state->guest_CC_DEP1, |
| vex_state->guest_CC_DEP2 |
| ); |
| return flags; |
| } |
| |
| /* VISIBLE TO LIBVEX CLIENT */ |
| void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state ) |
| { |
| vex_state->guest_R0 = 0; |
| vex_state->guest_R1 = 0; |
| vex_state->guest_R2 = 0; |
| vex_state->guest_R3 = 0; |
| vex_state->guest_R4 = 0; |
| vex_state->guest_R5 = 0; |
| vex_state->guest_R6 = 0; |
| vex_state->guest_R7 = 0; |
| vex_state->guest_R8 = 0; |
| vex_state->guest_R9 = 0; |
| vex_state->guest_R10 = 0; |
| vex_state->guest_R11 = 0; |
| vex_state->guest_R12 = 0; |
| vex_state->guest_R13 = 0; |
| vex_state->guest_R14 = 0; |
| vex_state->guest_R15 = 0; |
| |
| // CAB: Want this? |
| //vex_state->guest_SYSCALLNO = 0; |
| |
| vex_state->guest_CC_OP = 0;// CAB: ? ARMG_CC_OP_COPY; |
| vex_state->guest_CC_DEP1 = 0; |
| vex_state->guest_CC_DEP2 = 0; |
| |
| // CAB: Want this? |
| //vex_state->guest_EMWARN = 0; |
| |
| vex_state->guest_SYSCALLNO = 0; |
| } |
| |
| |
| /*-----------------------------------------------------------*/ |
| /*--- Describing the arm 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). |
| |
| We enforce precise exns for guest %ESP and %EIP only. |
| */ |
| Bool guest_arm_state_requires_precise_mem_exns ( Int minoff, |
| Int maxoff) |
| { |
| return True; // FIXME (also comment above) |
| #if 0 |
| Int esp_min = offsetof(VexGuestX86State, guest_ESP); |
| Int esp_max = esp_min + 4 - 1; |
| Int eip_min = offsetof(VexGuestX86State, guest_EIP); |
| Int eip_max = eip_min + 4 - 1; |
| |
| if (maxoff < esp_min || minoff > esp_max) { |
| /* no overlap with esp */ |
| } else { |
| return True; |
| } |
| |
| if (maxoff < eip_min || minoff > eip_max) { |
| /* no overlap with eip */ |
| } else { |
| return True; |
| } |
| |
| return False; |
| #endif |
| } |
| |
| |
| |
| #define ALWAYSDEFD(field) \ |
| { offsetof(VexGuestARMState, field), \ |
| (sizeof ((VexGuestARMState*)0)->field) } |
| |
| VexGuestLayout |
| armGuest_layout |
| = { |
| /* Total size of the guest state, in bytes. */ |
| .total_sizeB = sizeof(VexGuestARMState), |
| |
| /* Describe the stack pointer. */ |
| .offset_SP = offsetof(VexGuestARMState,guest_R13), |
| .sizeof_SP = 4, |
| |
| /* Describe the instruction pointer. */ |
| .offset_IP = offsetof(VexGuestARMState,guest_R15), |
| .sizeof_IP = 4, |
| |
| /* Describe any sections to be regarded by Memcheck as |
| 'always-defined'. */ |
| .n_alwaysDefd = 2, |
| /* flags thunk: OP is always defd, whereas DEP1 and DEP2 |
| have to be tracked. See detailed comment in gdefs.h on |
| meaning of thunk fields. */ |
| |
| .alwaysDefd |
| = { /* 0 */ ALWAYSDEFD(guest_CC_OP), |
| /* 1 */ ALWAYSDEFD(guest_SYSCALLNO) |
| } |
| }; |
| |
| |
| /*---------------------------------------------------------------*/ |
| /*--- end guest-arm/ghelpers.c ---*/ |
| /*---------------------------------------------------------------*/ |