Home | History | Annotate | Download | only in priv
      1 
      2 /*---------------------------------------------------------------*/
      3 /*--- begin                               guest_arm_helpers.c ---*/
      4 /*---------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2004-2011 OpenWorks LLP
     11       info (at) open-works.net
     12 
     13    This program is free software; you can redistribute it and/or
     14    modify it under the terms of the GNU General Public License as
     15    published by the Free Software Foundation; either version 2 of the
     16    License, or (at your option) any later version.
     17 
     18    This program is distributed in the hope that it will be useful, but
     19    WITHOUT ANY WARRANTY; without even the implied warranty of
     20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     21    General Public License for more details.
     22 
     23    You should have received a copy of the GNU General Public License
     24    along with this program; if not, write to the Free Software
     25    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
     26    02110-1301, USA.
     27 
     28    The GNU General Public License is contained in the file COPYING.
     29 */
     30 
     31 #include "libvex_basictypes.h"
     32 #include "libvex_emwarn.h"
     33 #include "libvex_guest_arm.h"
     34 #include "libvex_ir.h"
     35 #include "libvex.h"
     36 
     37 #include "main_util.h"
     38 #include "guest_generic_bb_to_IR.h"
     39 #include "guest_arm_defs.h"
     40 
     41 
     42 /* This file contains helper functions for arm guest code.  Calls to
     43    these functions are generated by the back end.  These calls are of
     44    course in the host machine code and this file will be compiled to
     45    host machine code, so that all makes sense.
     46 
     47    Only change the signatures of these helper functions very
     48    carefully.  If you change the signature here, you'll have to change
     49    the parameters passed to it in the IR calls constructed by
     50    guest-arm/toIR.c.
     51 */
     52 
     53 
     54 /* Set to 1 to get detailed profiling info about individual N, Z, C
     55    and V flag evaluation. */
     56 #define PROFILE_NZCV_FLAGS 0
     57 
     58 #if PROFILE_NZCV_FLAGS
     59 
     60 static UInt tab_n_eval[ARMG_CC_OP_NUMBER];
     61 static UInt tab_z_eval[ARMG_CC_OP_NUMBER];
     62 static UInt tab_c_eval[ARMG_CC_OP_NUMBER];
     63 static UInt tab_v_eval[ARMG_CC_OP_NUMBER];
     64 static UInt initted = 0;
     65 static UInt tot_evals = 0;
     66 
     67 static void initCounts ( void )
     68 {
     69    UInt i;
     70    for (i = 0; i < ARMG_CC_OP_NUMBER; i++) {
     71       tab_n_eval[i] = tab_z_eval[i] = tab_c_eval[i] = tab_v_eval[i] = 0;
     72    }
     73    initted = 1;
     74 }
     75 
     76 static void showCounts ( void )
     77 {
     78    UInt i;
     79    vex_printf("\n                 N          Z          C          V\n");
     80    vex_printf(  "---------------------------------------------------\n");
     81    for (i = 0; i < ARMG_CC_OP_NUMBER; i++) {
     82       vex_printf("CC_OP=%d  %9d  %9d  %9d  %9d\n",
     83                  i,
     84                  tab_n_eval[i], tab_z_eval[i],
     85                  tab_c_eval[i], tab_v_eval[i] );
     86     }
     87 }
     88 
     89 #define NOTE_N_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_n_eval)
     90 #define NOTE_Z_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_z_eval)
     91 #define NOTE_C_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_c_eval)
     92 #define NOTE_V_EVAL(_cc_op) NOTE_EVAL(_cc_op, tab_v_eval)
     93 
     94 #define NOTE_EVAL(_cc_op, _tab) \
     95    do { \
     96       if (!initted) initCounts(); \
     97       vassert( ((UInt)(_cc_op)) < ARMG_CC_OP_NUMBER); \
     98       _tab[(UInt)(_cc_op)]++; \
     99       tot_evals++; \
    100       if (0 == (tot_evals & 0xFFFFF)) \
    101         showCounts(); \
    102    } while (0)
    103 
    104 #endif /* PROFILE_NZCV_FLAGS */
    105 
    106 
    107 /* Calculate the N flag from the supplied thunk components, in the
    108    least significant bit of the word.  Returned bits 31:1 are zero. */
    109 static
    110 UInt armg_calculate_flag_n ( UInt cc_op, UInt cc_dep1,
    111                              UInt cc_dep2, UInt cc_dep3 )
    112 {
    113 #  if PROFILE_NZCV_FLAGS
    114    NOTE_N_EVAL(cc_op);
    115 #  endif
    116 
    117    switch (cc_op) {
    118       case ARMG_CC_OP_COPY: {
    119          /* (nzcv:28x0, unused, unused) */
    120          UInt nf   = (cc_dep1 >> ARMG_CC_SHIFT_N) & 1;
    121          return nf;
    122       }
    123       case ARMG_CC_OP_ADD: {
    124          /* (argL, argR, unused) */
    125          UInt argL = cc_dep1;
    126          UInt argR = cc_dep2;
    127          UInt res  = argL + argR;
    128          UInt nf   = res >> 31;
    129          return nf;
    130       }
    131       case ARMG_CC_OP_SUB: {
    132          /* (argL, argR, unused) */
    133          UInt argL = cc_dep1;
    134          UInt argR = cc_dep2;
    135          UInt res  = argL - argR;
    136          UInt nf   = res >> 31;
    137          return nf;
    138       }
    139       case ARMG_CC_OP_ADC: {
    140          /* (argL, argR, oldC) */
    141          UInt argL = cc_dep1;
    142          UInt argR = cc_dep2;
    143          UInt oldC = cc_dep3;
    144          vassert((oldC & ~1) == 0);
    145          UInt res  = argL + argR + oldC;
    146          UInt nf   = res >> 31;
    147          return nf;
    148       }
    149       case ARMG_CC_OP_SBB: {
    150          /* (argL, argR, oldC) */
    151          UInt argL = cc_dep1;
    152          UInt argR = cc_dep2;
    153          UInt oldC = cc_dep3;
    154          vassert((oldC & ~1) == 0);
    155          UInt res  = argL - argR - (oldC ^ 1);
    156          UInt nf   = res >> 31;
    157          return nf;
    158       }
    159       case ARMG_CC_OP_LOGIC: {
    160          /* (res, shco, oldV) */
    161          UInt res  = cc_dep1;
    162          UInt nf   = res >> 31;
    163          return nf;
    164       }
    165       case ARMG_CC_OP_MUL: {
    166          /* (res, unused, oldC:oldV) */
    167          UInt res  = cc_dep1;
    168          UInt nf   = res >> 31;
    169          return nf;
    170       }
    171       case ARMG_CC_OP_MULL: {
    172          /* (resLo32, resHi32, oldC:oldV) */
    173          UInt resHi32 = cc_dep2;
    174          UInt nf      = resHi32 >> 31;
    175          return nf;
    176       }
    177       default:
    178          /* shouldn't really make these calls from generated code */
    179          vex_printf("armg_calculate_flag_n"
    180                     "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n",
    181                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
    182          vpanic("armg_calculate_flags_n");
    183    }
    184 }
    185 
    186 
    187 /* Calculate the Z flag from the supplied thunk components, in the
    188    least significant bit of the word.  Returned bits 31:1 are zero. */
    189 static
    190 UInt armg_calculate_flag_z ( UInt cc_op, UInt cc_dep1,
    191                              UInt cc_dep2, UInt cc_dep3 )
    192 {
    193 #  if PROFILE_NZCV_FLAGS
    194    NOTE_Z_EVAL(cc_op);
    195 #  endif
    196 
    197    switch (cc_op) {
    198       case ARMG_CC_OP_COPY: {
    199          /* (nzcv:28x0, unused, unused) */
    200          UInt zf   = (cc_dep1 >> ARMG_CC_SHIFT_Z) & 1;
    201          return zf;
    202       }
    203       case ARMG_CC_OP_ADD: {
    204          /* (argL, argR, unused) */
    205          UInt argL = cc_dep1;
    206          UInt argR = cc_dep2;
    207          UInt res  = argL + argR;
    208          UInt zf   = res == 0;
    209          return zf;
    210       }
    211       case ARMG_CC_OP_SUB: {
    212          /* (argL, argR, unused) */
    213          UInt argL = cc_dep1;
    214          UInt argR = cc_dep2;
    215          UInt res  = argL - argR;
    216          UInt zf   = res == 0;
    217          return zf;
    218       }
    219       case ARMG_CC_OP_ADC: {
    220          /* (argL, argR, oldC) */
    221          UInt argL = cc_dep1;
    222          UInt argR = cc_dep2;
    223          UInt oldC = cc_dep3;
    224          vassert((oldC & ~1) == 0);
    225          UInt res  = argL + argR + oldC;
    226          UInt zf   = res == 0;
    227          return zf;
    228       }
    229       case ARMG_CC_OP_SBB: {
    230          /* (argL, argR, oldC) */
    231          UInt argL = cc_dep1;
    232          UInt argR = cc_dep2;
    233          UInt oldC = cc_dep3;
    234          vassert((oldC & ~1) == 0);
    235          UInt res  = argL - argR - (oldC ^ 1);
    236          UInt zf   = res == 0;
    237          return zf;
    238       }
    239       case ARMG_CC_OP_LOGIC: {
    240          /* (res, shco, oldV) */
    241          UInt res  = cc_dep1;
    242          UInt zf   = res == 0;
    243          return zf;
    244       }
    245       case ARMG_CC_OP_MUL: {
    246          /* (res, unused, oldC:oldV) */
    247          UInt res  = cc_dep1;
    248          UInt zf   = res == 0;
    249          return zf;
    250       }
    251       case ARMG_CC_OP_MULL: {
    252          /* (resLo32, resHi32, oldC:oldV) */
    253          UInt resLo32 = cc_dep1;
    254          UInt resHi32 = cc_dep2;
    255          UInt zf      = (resHi32|resLo32) == 0;
    256          return zf;
    257       }
    258       default:
    259          /* shouldn't really make these calls from generated code */
    260          vex_printf("armg_calculate_flags_z"
    261                     "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n",
    262                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
    263          vpanic("armg_calculate_flags_z");
    264    }
    265 }
    266 
    267 
    268 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
    269 /* Calculate the C flag from the supplied thunk components, in the
    270    least significant bit of the word.  Returned bits 31:1 are zero. */
    271 UInt armg_calculate_flag_c ( UInt cc_op, UInt cc_dep1,
    272                              UInt cc_dep2, UInt cc_dep3 )
    273 {
    274 #  if PROFILE_NZCV_FLAGS
    275    NOTE_C_EVAL(cc_op);
    276 #  endif
    277 
    278    switch (cc_op) {
    279       case ARMG_CC_OP_COPY: {
    280          /* (nzcv:28x0, unused, unused) */
    281          UInt cf   = (cc_dep1 >> ARMG_CC_SHIFT_C) & 1;
    282          return cf;
    283       }
    284       case ARMG_CC_OP_ADD: {
    285          /* (argL, argR, unused) */
    286          UInt argL = cc_dep1;
    287          UInt argR = cc_dep2;
    288          UInt res  = argL + argR;
    289          UInt cf   = res < argL;
    290          return cf;
    291       }
    292       case ARMG_CC_OP_SUB: {
    293          /* (argL, argR, unused) */
    294          UInt argL = cc_dep1;
    295          UInt argR = cc_dep2;
    296          UInt cf   = argL >= argR;
    297          return cf;
    298       }
    299       case ARMG_CC_OP_ADC: {
    300          /* (argL, argR, oldC) */
    301          UInt argL = cc_dep1;
    302          UInt argR = cc_dep2;
    303          UInt oldC = cc_dep3;
    304          vassert((oldC & ~1) == 0);
    305          UInt res  = argL + argR + oldC;
    306          UInt cf   = oldC ? (res <= argL) : (res < argL);
    307          return cf;
    308       }
    309       case ARMG_CC_OP_SBB: {
    310          /* (argL, argR, oldC) */
    311          UInt argL = cc_dep1;
    312          UInt argR = cc_dep2;
    313          UInt oldC = cc_dep3;
    314          vassert((oldC & ~1) == 0);
    315          UInt cf   = oldC ? (argL >= argR) : (argL > argR);
    316          return cf;
    317       }
    318       case ARMG_CC_OP_LOGIC: {
    319          /* (res, shco, oldV) */
    320          UInt shco = cc_dep2;
    321          vassert((shco & ~1) == 0);
    322          UInt cf   = shco;
    323          return cf;
    324       }
    325       case ARMG_CC_OP_MUL: {
    326          /* (res, unused, oldC:oldV) */
    327          UInt oldC = (cc_dep3 >> 1) & 1;
    328          vassert((cc_dep3 & ~3) == 0);
    329          UInt cf   = oldC;
    330          return cf;
    331       }
    332       case ARMG_CC_OP_MULL: {
    333          /* (resLo32, resHi32, oldC:oldV) */
    334          UInt oldC    = (cc_dep3 >> 1) & 1;
    335          vassert((cc_dep3 & ~3) == 0);
    336          UInt cf      = oldC;
    337          return cf;
    338       }
    339       default:
    340          /* shouldn't really make these calls from generated code */
    341          vex_printf("armg_calculate_flag_c"
    342                     "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n",
    343                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
    344          vpanic("armg_calculate_flag_c");
    345    }
    346 }
    347 
    348 
    349 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
    350 /* Calculate the V flag from the supplied thunk components, in the
    351    least significant bit of the word.  Returned bits 31:1 are zero. */
    352 UInt armg_calculate_flag_v ( UInt cc_op, UInt cc_dep1,
    353                              UInt cc_dep2, UInt cc_dep3 )
    354 {
    355 #  if PROFILE_NZCV_FLAGS
    356    NOTE_V_EVAL(cc_op);
    357 #  endif
    358 
    359    switch (cc_op) {
    360       case ARMG_CC_OP_COPY: {
    361          /* (nzcv:28x0, unused, unused) */
    362          UInt vf   = (cc_dep1 >> ARMG_CC_SHIFT_V) & 1;
    363          return vf;
    364       }
    365       case ARMG_CC_OP_ADD: {
    366          /* (argL, argR, unused) */
    367          UInt argL = cc_dep1;
    368          UInt argR = cc_dep2;
    369          UInt res  = argL + argR;
    370          UInt vf   = ((res ^ argL) & (res ^ argR)) >> 31;
    371          return vf;
    372       }
    373       case ARMG_CC_OP_SUB: {
    374          /* (argL, argR, unused) */
    375          UInt argL = cc_dep1;
    376          UInt argR = cc_dep2;
    377          UInt res  = argL - argR;
    378          UInt vf   = ((argL ^ argR) & (argL ^ res)) >> 31;
    379          return vf;
    380       }
    381       case ARMG_CC_OP_ADC: {
    382          /* (argL, argR, oldC) */
    383          UInt argL = cc_dep1;
    384          UInt argR = cc_dep2;
    385          UInt oldC = cc_dep3;
    386          vassert((oldC & ~1) == 0);
    387          UInt res  = argL + argR + oldC;
    388          UInt vf   = ((res ^ argL) & (res ^ argR)) >> 31;
    389          return vf;
    390       }
    391       case ARMG_CC_OP_SBB: {
    392          /* (argL, argR, oldC) */
    393          UInt argL = cc_dep1;
    394          UInt argR = cc_dep2;
    395          UInt oldC = cc_dep3;
    396          vassert((oldC & ~1) == 0);
    397          UInt res  = argL - argR - (oldC ^ 1);
    398          UInt vf   = ((argL ^ argR) & (argL ^ res)) >> 31;
    399          return vf;
    400       }
    401       case ARMG_CC_OP_LOGIC: {
    402          /* (res, shco, oldV) */
    403          UInt oldV = cc_dep3;
    404          vassert((oldV & ~1) == 0);
    405          UInt vf   = oldV;
    406          return vf;
    407       }
    408       case ARMG_CC_OP_MUL: {
    409          /* (res, unused, oldC:oldV) */
    410          UInt oldV = (cc_dep3 >> 0) & 1;
    411          vassert((cc_dep3 & ~3) == 0);
    412          UInt vf   = oldV;
    413          return vf;
    414       }
    415       case ARMG_CC_OP_MULL: {
    416          /* (resLo32, resHi32, oldC:oldV) */
    417          UInt oldV    = (cc_dep3 >> 0) & 1;
    418          vassert((cc_dep3 & ~3) == 0);
    419          UInt vf      = oldV;
    420          return vf;
    421       }
    422       default:
    423          /* shouldn't really make these calls from generated code */
    424          vex_printf("armg_calculate_flag_v"
    425                     "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n",
    426                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
    427          vpanic("armg_calculate_flag_v");
    428    }
    429 }
    430 
    431 
    432 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
    433 /* Calculate NZCV from the supplied thunk components, in the positions
    434    they appear in the CPSR, viz bits 31:28 for N Z C V respectively.
    435    Returned bits 27:0 are zero. */
    436 UInt armg_calculate_flags_nzcv ( UInt cc_op, UInt cc_dep1,
    437                                  UInt cc_dep2, UInt cc_dep3 )
    438 {
    439    UInt f;
    440    UInt res = 0;
    441    f = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
    442    res |= (f << ARMG_CC_SHIFT_N);
    443    f = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
    444    res |= (f << ARMG_CC_SHIFT_Z);
    445    f = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
    446    res |= (f << ARMG_CC_SHIFT_C);
    447    f = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
    448    res |= (f << ARMG_CC_SHIFT_V);
    449    return res;
    450 }
    451 
    452 
    453 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
    454 /* Calculate the QC flag from the arguments, in the lowest bit
    455    of the word (bit 0).  Urr, having this out of line is bizarre.
    456    Push back inline. */
    457 UInt armg_calculate_flag_qc ( UInt resL1, UInt resL2,
    458                               UInt resR1, UInt resR2 )
    459 {
    460    if (resL1 != resR1 || resL2 != resR2)
    461       return 1;
    462    else
    463       return 0;
    464 }
    465 
    466 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
    467 /* Calculate the specified condition from the thunk components, in the
    468    lowest bit of the word (bit 0).  Returned bits 31:1 are zero. */
    469 UInt armg_calculate_condition ( UInt cond_n_op /* (ARMCondcode << 4) | cc_op */,
    470                                 UInt cc_dep1,
    471                                 UInt cc_dep2, UInt cc_dep3 )
    472 {
    473    UInt cond  = cond_n_op >> 4;
    474    UInt cc_op = cond_n_op & 0xF;
    475    UInt nf, zf, vf, cf, inv;
    476    //   vex_printf("XXXXXXXX %x %x %x %x\n",
    477    //              cond_n_op, cc_dep1, cc_dep2, cc_dep3);
    478 
    479    // skip flags computation in this case
    480    if (cond == ARMCondAL) return 1;
    481 
    482    inv  = cond & 1;
    483 
    484    switch (cond) {
    485       case ARMCondEQ:    // Z=1         => z
    486       case ARMCondNE:    // Z=0
    487          zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
    488          return inv ^ zf;
    489 
    490       case ARMCondHS:    // C=1         => c
    491       case ARMCondLO:    // C=0
    492          cf = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
    493          return inv ^ cf;
    494 
    495       case ARMCondMI:    // N=1         => n
    496       case ARMCondPL:    // N=0
    497          nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
    498          return inv ^ nf;
    499 
    500       case ARMCondVS:    // V=1         => v
    501       case ARMCondVC:    // V=0
    502          vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
    503          return inv ^ vf;
    504 
    505       case ARMCondHI:    // C=1 && Z=0   => c & ~z
    506       case ARMCondLS:    // C=0 || Z=1
    507          cf = armg_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
    508          zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
    509          return inv ^ (cf & ~zf);
    510 
    511       case ARMCondGE:    // N=V          => ~(n^v)
    512       case ARMCondLT:    // N!=V
    513          nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
    514          vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
    515          return inv ^ (1 & ~(nf ^ vf));
    516 
    517       case ARMCondGT:    // Z=0 && N=V   => ~z & ~(n^v)  =>  ~(z | (n^v))
    518       case ARMCondLE:    // Z=1 || N!=V
    519          nf = armg_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
    520          vf = armg_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
    521          zf = armg_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
    522          return inv ^ (1 & ~(zf | (nf ^ vf)));
    523 
    524       case ARMCondAL: // handled above
    525       case ARMCondNV: // should never get here: Illegal instr
    526       default:
    527          /* shouldn't really make these calls from generated code */
    528          vex_printf("armg_calculate_condition(ARM)"
    529                     "( %u, %u, 0x%x, 0x%x, 0x%x )\n",
    530                     cond, cc_op, cc_dep1, cc_dep2, cc_dep3 );
    531          vpanic("armg_calculate_condition(ARM)");
    532    }
    533 }
    534 
    535 
    536 /*---------------------------------------------------------------*/
    537 /*--- Flag-helpers translation-time function specialisers.    ---*/
    538 /*--- These help iropt specialise calls the above run-time    ---*/
    539 /*--- flags functions.                                        ---*/
    540 /*---------------------------------------------------------------*/
    541 
    542 /* Used by the optimiser to try specialisations.  Returns an
    543    equivalent expression, or NULL if none. */
    544 
    545 static Bool isU32 ( IRExpr* e, UInt n )
    546 {
    547    return
    548       toBool( e->tag == Iex_Const
    549               && e->Iex.Const.con->tag == Ico_U32
    550               && e->Iex.Const.con->Ico.U32 == n );
    551 }
    552 
    553 IRExpr* guest_arm_spechelper ( HChar*   function_name,
    554                                IRExpr** args,
    555                                IRStmt** precedingStmts,
    556                                Int      n_precedingStmts )
    557 {
    558 #  define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
    559 #  define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
    560 #  define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
    561 #  define mkU8(_n)  IRExpr_Const(IRConst_U8(_n))
    562 
    563    Int i, arity = 0;
    564    for (i = 0; args[i]; i++)
    565       arity++;
    566 #  if 0
    567    vex_printf("spec request:\n");
    568    vex_printf("   %s  ", function_name);
    569    for (i = 0; i < arity; i++) {
    570       vex_printf("  ");
    571       ppIRExpr(args[i]);
    572    }
    573    vex_printf("\n");
    574 #  endif
    575 
    576    /* --------- specialising "armg_calculate_condition" --------- */
    577 
    578    if (vex_streq(function_name, "armg_calculate_condition")) {
    579 
    580       /* specialise calls to the "armg_calculate_condition" function.
    581          Not sure whether this is strictly necessary, but: the
    582          replacement IR must produce only the values 0 or 1.  Bits
    583          31:1 are required to be zero. */
    584       IRExpr *cond_n_op, *cc_dep1, *cc_dep2, *cc_ndep;
    585       vassert(arity == 4);
    586       cond_n_op = args[0]; /* (ARMCondcode << 4)  |  ARMG_CC_OP_* */
    587       cc_dep1   = args[1];
    588       cc_dep2   = args[2];
    589       cc_ndep   = args[3];
    590 
    591       /*---------------- SUB ----------------*/
    592 
    593       if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_SUB)) {
    594          /* EQ after SUB --> test argL == argR */
    595          return unop(Iop_1Uto32,
    596                      binop(Iop_CmpEQ32, cc_dep1, cc_dep2));
    597       }
    598       if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_SUB)) {
    599          /* NE after SUB --> test argL != argR */
    600          return unop(Iop_1Uto32,
    601                      binop(Iop_CmpNE32, cc_dep1, cc_dep2));
    602       }
    603 
    604       if (isU32(cond_n_op, (ARMCondGT << 4) | ARMG_CC_OP_SUB)) {
    605          /* GT after SUB --> test argL >s argR
    606                          --> test argR <s argL */
    607          return unop(Iop_1Uto32,
    608                      binop(Iop_CmpLT32S, cc_dep2, cc_dep1));
    609       }
    610       if (isU32(cond_n_op, (ARMCondLE << 4) | ARMG_CC_OP_SUB)) {
    611          /* LE after SUB --> test argL <=s argR */
    612          return unop(Iop_1Uto32,
    613                      binop(Iop_CmpLE32S, cc_dep1, cc_dep2));
    614       }
    615 
    616       if (isU32(cond_n_op, (ARMCondLT << 4) | ARMG_CC_OP_SUB)) {
    617          /* LT after SUB --> test argL <s argR */
    618          return unop(Iop_1Uto32,
    619                      binop(Iop_CmpLT32S, cc_dep1, cc_dep2));
    620       }
    621 
    622       if (isU32(cond_n_op, (ARMCondGE << 4) | ARMG_CC_OP_SUB)) {
    623          /* GE after SUB --> test argL >=s argR
    624                          --> test argR <=s argL */
    625          return unop(Iop_1Uto32,
    626                      binop(Iop_CmpLE32S, cc_dep2, cc_dep1));
    627       }
    628 
    629       if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SUB)) {
    630          /* HS after SUB --> test argL >=u argR
    631                          --> test argR <=u argL */
    632          return unop(Iop_1Uto32,
    633                      binop(Iop_CmpLE32U, cc_dep2, cc_dep1));
    634       }
    635       if (isU32(cond_n_op, (ARMCondLO << 4) | ARMG_CC_OP_SUB)) {
    636          /* LO after SUB --> test argL <u argR */
    637          return unop(Iop_1Uto32,
    638                      binop(Iop_CmpLT32U, cc_dep1, cc_dep2));
    639       }
    640 
    641       if (isU32(cond_n_op, (ARMCondLS << 4) | ARMG_CC_OP_SUB)) {
    642          /* LS after SUB --> test argL <=u argR */
    643          return unop(Iop_1Uto32,
    644                      binop(Iop_CmpLE32U, cc_dep1, cc_dep2));
    645       }
    646 
    647       /*---------------- SBB ----------------*/
    648 
    649       if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SBB)) {
    650          /* This seems to happen a lot in softfloat code, eg __divdf3+140 */
    651          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
    652          /* HS after SBB (same as C after SBB below)
    653             --> oldC ? (argL >=u argR) : (argL >u argR)
    654             --> oldC ? (argR <=u argL) : (argR <u argL)
    655          */
    656          return
    657             IRExpr_Mux0X(
    658                unop(Iop_32to8, cc_ndep),
    659                /* case oldC == 0 */
    660                unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1)),
    661                /* case oldC != 0 */
    662                unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1))
    663             );
    664       }
    665 
    666       /*---------------- LOGIC ----------------*/
    667 
    668       if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_LOGIC)) {
    669          /* EQ after LOGIC --> test res == 0 */
    670          return unop(Iop_1Uto32,
    671                      binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
    672       }
    673       if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_LOGIC)) {
    674          /* NE after LOGIC --> test res != 0 */
    675          return unop(Iop_1Uto32,
    676                      binop(Iop_CmpNE32, cc_dep1, mkU32(0)));
    677       }
    678 
    679       if (isU32(cond_n_op, (ARMCondPL << 4) | ARMG_CC_OP_LOGIC)) {
    680          /* PL after LOGIC --> test (res >> 31) == 0 */
    681          return unop(Iop_1Uto32,
    682                      binop(Iop_CmpEQ32,
    683                            binop(Iop_Shr32, cc_dep1, mkU8(31)),
    684                            mkU32(0)));
    685       }
    686       if (isU32(cond_n_op, (ARMCondMI << 4) | ARMG_CC_OP_LOGIC)) {
    687          /* MI after LOGIC --> test (res >> 31) == 1 */
    688          return unop(Iop_1Uto32,
    689                      binop(Iop_CmpEQ32,
    690                            binop(Iop_Shr32, cc_dep1, mkU8(31)),
    691                            mkU32(1)));
    692       }
    693 
    694       /*----------------- AL -----------------*/
    695 
    696       /* A critically important case for Thumb code.
    697 
    698          What we're trying to spot is the case where cond_n_op is an
    699          expression of the form Or32(..., 0xE0) since that means the
    700          caller is asking for CondAL and we can simply return 1
    701          without caring what the ... part is.  This is a potentially
    702          dodgy kludge in that it assumes that the ... part has zeroes
    703          in bits 7:4, so that the result of the Or32 is guaranteed to
    704          be 0xE in bits 7:4.  Given that the places where this first
    705          arg are constructed (in guest_arm_toIR.c) are very
    706          constrained, we can get away with this.  To make this
    707          guaranteed safe would require to have a new primop, Slice44
    708          or some such, thusly
    709 
    710          Slice44(arg1, arg2) = 0--(24)--0 arg1[7:4] arg2[3:0]
    711 
    712          and we would then look for Slice44(0xE0, ...)
    713          which would give the required safety property.
    714 
    715          It would be infeasibly expensive to scan backwards through
    716          the entire block looking for an assignment to the temp, so
    717          just look at the previous 16 statements.  That should find it
    718          if it is an interesting case, as a result of how the
    719          boilerplate guff at the start of each Thumb insn translation
    720          is made.
    721       */
    722       if (cond_n_op->tag == Iex_RdTmp) {
    723          Int    j;
    724          IRTemp look_for = cond_n_op->Iex.RdTmp.tmp;
    725          Int    limit    = n_precedingStmts - 16;
    726          if (limit < 0) limit = 0;
    727          if (0) vex_printf("scanning %d .. %d\n", n_precedingStmts-1, limit);
    728          for (j = n_precedingStmts - 1; j >= limit; j--) {
    729             IRStmt* st = precedingStmts[j];
    730             if (st->tag == Ist_WrTmp
    731                 && st->Ist.WrTmp.tmp == look_for
    732                 && st->Ist.WrTmp.data->tag == Iex_Binop
    733                 && st->Ist.WrTmp.data->Iex.Binop.op == Iop_Or32
    734                 && isU32(st->Ist.WrTmp.data->Iex.Binop.arg2, (ARMCondAL << 4)))
    735                return mkU32(1);
    736          }
    737          /* Didn't find any useful binding to the first arg
    738             in the previous 16 stmts. */
    739       }
    740    }
    741 
    742    /* --------- specialising "armg_calculate_flag_c" --------- */
    743 
    744    else
    745    if (vex_streq(function_name, "armg_calculate_flag_c")) {
    746 
    747       /* specialise calls to the "armg_calculate_flag_c" function.
    748          Note that the returned value must be either 0 or 1; nonzero
    749          bits 31:1 are not allowed.  In turn, incoming oldV and oldC
    750          values (from the thunk) are assumed to have bits 31:1
    751          clear. */
    752       IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
    753       vassert(arity == 4);
    754       cc_op   = args[0]; /* ARMG_CC_OP_* */
    755       cc_dep1 = args[1];
    756       cc_dep2 = args[2];
    757       cc_ndep = args[3];
    758 
    759       if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
    760          /* Thunk args are (result, shco, oldV) */
    761          /* C after LOGIC --> shco */
    762          return cc_dep2;
    763       }
    764 
    765       if (isU32(cc_op, ARMG_CC_OP_SUB)) {
    766          /* Thunk args are (argL, argR, unused) */
    767          /* C after SUB --> argL >=u argR
    768                         --> argR <=u argL */
    769          return unop(Iop_1Uto32,
    770                      binop(Iop_CmpLE32U, cc_dep2, cc_dep1));
    771       }
    772 
    773       if (isU32(cc_op, ARMG_CC_OP_SBB)) {
    774          /* This happens occasionally in softfloat code, eg __divdf3+140 */
    775          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
    776          /* C after SBB (same as HS after SBB above)
    777             --> oldC ? (argL >=u argR) : (argL >u argR)
    778             --> oldC ? (argR <=u argL) : (argR <u argL)
    779          */
    780          return
    781             IRExpr_Mux0X(
    782                unop(Iop_32to8, cc_ndep),
    783                /* case oldC == 0 */
    784                unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1)),
    785                /* case oldC != 0 */
    786                unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1))
    787             );
    788       }
    789 
    790    }
    791 
    792    /* --------- specialising "armg_calculate_flag_v" --------- */
    793 
    794    else
    795    if (vex_streq(function_name, "armg_calculate_flag_v")) {
    796 
    797       /* specialise calls to the "armg_calculate_flag_v" function.
    798          Note that the returned value must be either 0 or 1; nonzero
    799          bits 31:1 are not allowed.  In turn, incoming oldV and oldC
    800          values (from the thunk) are assumed to have bits 31:1
    801          clear. */
    802       IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
    803       vassert(arity == 4);
    804       cc_op   = args[0]; /* ARMG_CC_OP_* */
    805       cc_dep1 = args[1];
    806       cc_dep2 = args[2];
    807       cc_ndep = args[3];
    808 
    809       if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
    810          /* Thunk args are (result, shco, oldV) */
    811          /* V after LOGIC --> oldV */
    812          return cc_ndep;
    813       }
    814 
    815       if (isU32(cc_op, ARMG_CC_OP_SUB)) {
    816          /* Thunk args are (argL, argR, unused) */
    817          /* V after SUB
    818             --> let res = argL - argR
    819                 in ((argL ^ argR) & (argL ^ res)) >> 31
    820             --> ((argL ^ argR) & (argL ^ (argL - argR))) >> 31
    821          */
    822          IRExpr* argL = cc_dep1;
    823          IRExpr* argR = cc_dep2;
    824          return
    825             binop(Iop_Shr32,
    826                   binop(Iop_And32,
    827                         binop(Iop_Xor32, argL, argR),
    828                         binop(Iop_Xor32, argL, binop(Iop_Sub32, argL, argR))
    829                   ),
    830                   mkU8(31)
    831             );
    832       }
    833 
    834       if (isU32(cc_op, ARMG_CC_OP_SBB)) {
    835          /* This happens occasionally in softfloat code, eg __divdf3+140 */
    836          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
    837          /* V after SBB
    838             --> let res = argL - argR - (oldC ^ 1)
    839                 in  (argL ^ argR) & (argL ^ res) & 1
    840          */
    841          return
    842             binop(
    843                Iop_And32,
    844                binop(
    845                   Iop_And32,
    846                   // argL ^ argR
    847                   binop(Iop_Xor32, cc_dep1, cc_dep2),
    848                   // argL ^ (argL - argR - (oldC ^ 1))
    849                   binop(Iop_Xor32,
    850                         cc_dep1,
    851                         binop(Iop_Sub32,
    852                               binop(Iop_Sub32, cc_dep1, cc_dep2),
    853                               binop(Iop_Xor32, cc_ndep, mkU32(1)))
    854                   )
    855                ),
    856                mkU32(1)
    857             );
    858       }
    859 
    860    }
    861 
    862 #  undef unop
    863 #  undef binop
    864 #  undef mkU32
    865 #  undef mkU8
    866 
    867    return NULL;
    868 }
    869 
    870 
    871 /*----------------------------------------------*/
    872 /*--- The exported fns ..                    ---*/
    873 /*----------------------------------------------*/
    874 
    875 /* VISIBLE TO LIBVEX CLIENT */
    876 #if 0
    877 void LibVEX_GuestARM_put_flags ( UInt flags_native,
    878                                  /*OUT*/VexGuestARMState* vex_state )
    879 {
    880    vassert(0); // FIXME
    881 
    882    /* Mask out everything except N Z V C. */
    883    flags_native
    884       &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z | ARMG_CC_MASK_V | ARMG_CC_MASK_C);
    885 
    886    vex_state->guest_CC_OP   = ARMG_CC_OP_COPY;
    887    vex_state->guest_CC_DEP1 = flags_native;
    888    vex_state->guest_CC_DEP2 = 0;
    889    vex_state->guest_CC_NDEP = 0;
    890 }
    891 #endif
    892 
    893 /* VISIBLE TO LIBVEX CLIENT */
    894 UInt LibVEX_GuestARM_get_cpsr ( /*IN*/VexGuestARMState* vex_state )
    895 {
    896    UInt cpsr = 0;
    897    // NZCV
    898    cpsr |= armg_calculate_flags_nzcv(
    899                vex_state->guest_CC_OP,
    900                vex_state->guest_CC_DEP1,
    901                vex_state->guest_CC_DEP2,
    902                vex_state->guest_CC_NDEP
    903             );
    904    vassert(0 == (cpsr & 0x0FFFFFFF));
    905    // Q
    906    if (vex_state->guest_QFLAG32 > 0)
    907       cpsr |= (1 << 27);
    908    // GE
    909    if (vex_state->guest_GEFLAG0 > 0)
    910       cpsr |= (1 << 16);
    911    if (vex_state->guest_GEFLAG1 > 0)
    912       cpsr |= (1 << 17);
    913    if (vex_state->guest_GEFLAG2 > 0)
    914       cpsr |= (1 << 18);
    915    if (vex_state->guest_GEFLAG3 > 0)
    916       cpsr |= (1 << 19);
    917    // M
    918    cpsr |= (1 << 4); // 0b10000 means user-mode
    919    // J,T   J (bit 24) is zero by initialisation above
    920    // T  we copy from R15T[0]
    921    if (vex_state->guest_R15T & 1)
    922       cpsr |= (1 << 5);
    923    // ITSTATE we punt on for the time being.  Could compute it
    924    // if needed though.
    925    // E, endianness, 0 (littleendian) from initialisation above
    926    // A,I,F disable some async exceptions.  Not sure about these.
    927    // Leave as zero for the time being.
    928    return cpsr;
    929 }
    930 
    931 /* VISIBLE TO LIBVEX CLIENT */
    932 void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state )
    933 {
    934    vex_state->guest_R0  = 0;
    935    vex_state->guest_R1  = 0;
    936    vex_state->guest_R2  = 0;
    937    vex_state->guest_R3  = 0;
    938    vex_state->guest_R4  = 0;
    939    vex_state->guest_R5  = 0;
    940    vex_state->guest_R6  = 0;
    941    vex_state->guest_R7  = 0;
    942    vex_state->guest_R8  = 0;
    943    vex_state->guest_R9  = 0;
    944    vex_state->guest_R10 = 0;
    945    vex_state->guest_R11 = 0;
    946    vex_state->guest_R12 = 0;
    947    vex_state->guest_R13 = 0;
    948    vex_state->guest_R14 = 0;
    949    vex_state->guest_R15T = 0;  /* NB: implies ARM mode */
    950 
    951    vex_state->guest_CC_OP   = ARMG_CC_OP_COPY;
    952    vex_state->guest_CC_DEP1 = 0;
    953    vex_state->guest_CC_DEP2 = 0;
    954    vex_state->guest_CC_NDEP = 0;
    955    vex_state->guest_QFLAG32 = 0;
    956    vex_state->guest_GEFLAG0 = 0;
    957    vex_state->guest_GEFLAG1 = 0;
    958    vex_state->guest_GEFLAG2 = 0;
    959    vex_state->guest_GEFLAG3 = 0;
    960 
    961    vex_state->guest_EMWARN  = 0;
    962    vex_state->guest_TISTART = 0;
    963    vex_state->guest_TILEN   = 0;
    964    vex_state->guest_NRADDR  = 0;
    965    vex_state->guest_IP_AT_SYSCALL = 0;
    966 
    967    vex_state->guest_D0  = 0;
    968    vex_state->guest_D1  = 0;
    969    vex_state->guest_D2  = 0;
    970    vex_state->guest_D3  = 0;
    971    vex_state->guest_D4  = 0;
    972    vex_state->guest_D5  = 0;
    973    vex_state->guest_D6  = 0;
    974    vex_state->guest_D7  = 0;
    975    vex_state->guest_D8  = 0;
    976    vex_state->guest_D9  = 0;
    977    vex_state->guest_D10 = 0;
    978    vex_state->guest_D11 = 0;
    979    vex_state->guest_D12 = 0;
    980    vex_state->guest_D13 = 0;
    981    vex_state->guest_D14 = 0;
    982    vex_state->guest_D15 = 0;
    983    vex_state->guest_D16 = 0;
    984    vex_state->guest_D17 = 0;
    985    vex_state->guest_D18 = 0;
    986    vex_state->guest_D19 = 0;
    987    vex_state->guest_D20 = 0;
    988    vex_state->guest_D21 = 0;
    989    vex_state->guest_D22 = 0;
    990    vex_state->guest_D23 = 0;
    991    vex_state->guest_D24 = 0;
    992    vex_state->guest_D25 = 0;
    993    vex_state->guest_D26 = 0;
    994    vex_state->guest_D27 = 0;
    995    vex_state->guest_D28 = 0;
    996    vex_state->guest_D29 = 0;
    997    vex_state->guest_D30 = 0;
    998    vex_state->guest_D31 = 0;
    999 
   1000    /* ARM encoded; zero is the default as it happens (result flags
   1001       (NZCV) cleared, FZ disabled, round to nearest, non-vector mode,
   1002       all exns masked, all exn sticky bits cleared). */
   1003    vex_state->guest_FPSCR = 0;
   1004 
   1005    vex_state->guest_TPIDRURO = 0;
   1006 
   1007    /* Not in a Thumb IT block. */
   1008    vex_state->guest_ITSTATE = 0;
   1009 
   1010    vex_state->padding1 = 0;
   1011    vex_state->padding2 = 0;
   1012    vex_state->padding3 = 0;
   1013 }
   1014 
   1015 
   1016 /*-----------------------------------------------------------*/
   1017 /*--- Describing the arm guest state, for the benefit     ---*/
   1018 /*--- of iropt and instrumenters.                         ---*/
   1019 /*-----------------------------------------------------------*/
   1020 
   1021 /* Figure out if any part of the guest state contained in minoff
   1022    .. maxoff requires precise memory exceptions.  If in doubt return
   1023    True (but this is generates significantly slower code).
   1024 
   1025    We enforce precise exns for guest R13(sp), R15T(pc).
   1026 */
   1027 Bool guest_arm_state_requires_precise_mem_exns ( Int minoff,
   1028                                                  Int maxoff)
   1029 {
   1030    Int sp_min = offsetof(VexGuestARMState, guest_R13);
   1031    Int sp_max = sp_min + 4 - 1;
   1032    Int pc_min = offsetof(VexGuestARMState, guest_R15T);
   1033    Int pc_max = pc_min + 4 - 1;
   1034 
   1035    if (maxoff < sp_min || minoff > sp_max) {
   1036       /* no overlap with sp */
   1037    } else {
   1038       return True;
   1039    }
   1040 
   1041    if (maxoff < pc_min || minoff > pc_max) {
   1042       /* no overlap with pc */
   1043    } else {
   1044       return True;
   1045    }
   1046 
   1047    /* We appear to need precise updates of R11 in order to get proper
   1048       stacktraces from non-optimised code. */
   1049    Int r11_min = offsetof(VexGuestARMState, guest_R11);
   1050    Int r11_max = r11_min + 4 - 1;
   1051 
   1052    if (maxoff < r11_min || minoff > r11_max) {
   1053       /* no overlap with r11 */
   1054    } else {
   1055       return True;
   1056    }
   1057 
   1058    /* Ditto R7, particularly needed for proper stacktraces in Thumb
   1059       code. */
   1060    Int r7_min = offsetof(VexGuestARMState, guest_R7);
   1061    Int r7_max = r7_min + 4 - 1;
   1062 
   1063    if (maxoff < r7_min || minoff > r7_max) {
   1064       /* no overlap with r7 */
   1065    } else {
   1066       return True;
   1067    }
   1068 
   1069    return False;
   1070 }
   1071 
   1072 
   1073 
   1074 #define ALWAYSDEFD(field)                           \
   1075     { offsetof(VexGuestARMState, field),            \
   1076       (sizeof ((VexGuestARMState*)0)->field) }
   1077 
   1078 VexGuestLayout
   1079    armGuest_layout
   1080       = {
   1081           /* Total size of the guest state, in bytes. */
   1082           .total_sizeB = sizeof(VexGuestARMState),
   1083 
   1084           /* Describe the stack pointer. */
   1085           .offset_SP = offsetof(VexGuestARMState,guest_R13),
   1086           .sizeof_SP = 4,
   1087 
   1088           /* Describe the instruction pointer. */
   1089           .offset_IP = offsetof(VexGuestARMState,guest_R15T),
   1090           .sizeof_IP = 4,
   1091 
   1092           /* Describe any sections to be regarded by Memcheck as
   1093              'always-defined'. */
   1094           .n_alwaysDefd = 10,
   1095 
   1096           /* flags thunk: OP is always defd, whereas DEP1 and DEP2
   1097              have to be tracked.  See detailed comment in gdefs.h on
   1098              meaning of thunk fields. */
   1099           .alwaysDefd
   1100              = { /* 0 */ ALWAYSDEFD(guest_R15T),
   1101                  /* 1 */ ALWAYSDEFD(guest_CC_OP),
   1102                  /* 2 */ ALWAYSDEFD(guest_CC_NDEP),
   1103                  /* 3 */ ALWAYSDEFD(guest_EMWARN),
   1104                  /* 4 */ ALWAYSDEFD(guest_TISTART),
   1105                  /* 5 */ ALWAYSDEFD(guest_TILEN),
   1106                  /* 6 */ ALWAYSDEFD(guest_NRADDR),
   1107                  /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL),
   1108                  /* 8 */ ALWAYSDEFD(guest_TPIDRURO),
   1109                  /* 9 */ ALWAYSDEFD(guest_ITSTATE)
   1110                }
   1111         };
   1112 
   1113 
   1114 /*---------------------------------------------------------------*/
   1115 /*--- end                                 guest_arm_helpers.c ---*/
   1116 /*---------------------------------------------------------------*/
   1117