]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge in function wrapping support from the FNWRAP branch. That
authorJulian Seward <jseward@acm.org>
Thu, 12 Jan 2006 12:27:58 +0000 (12:27 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 12 Jan 2006 12:27:58 +0000 (12:27 +0000)
branch hereby becomes inactive.

git-svn-id: svn://svn.valgrind.org/vex/trunk@1536

21 files changed:
VEX/priv/guest-amd64/ghelpers.c
VEX/priv/guest-amd64/toIR.c
VEX/priv/guest-generic/bb_to_IR.c
VEX/priv/guest-generic/bb_to_IR.h
VEX/priv/guest-ppc/ghelpers.c
VEX/priv/guest-ppc/toIR.c
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-amd64/hdefs.c
VEX/priv/host-ppc/hdefs.c
VEX/priv/host-x86/hdefs.c
VEX/priv/ir/irdefs.c
VEX/priv/main/vex_main.c
VEX/pub/libvex.h
VEX/pub/libvex_guest_amd64.h
VEX/pub/libvex_guest_ppc32.h
VEX/pub/libvex_guest_ppc64.h
VEX/pub/libvex_guest_x86.h
VEX/pub/libvex_ir.h
VEX/pub/libvex_trc_values.h
VEX/test_main.c

index 70d0ff505fa0aca6c60af4e0c43b5ff4f9e0b288..8e8c707dde6be9f270c09aed66b522aaad1a470d 100644 (file)
@@ -1965,6 +1965,8 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state )
       initialise them anyway. */
    vex_state->guest_TISTART = 0;
    vex_state->guest_TILEN   = 0;
+
+   vex_state->guest_NRADDR = 0;
 }
 
 
index 1d6ec4dc39671af9870e41c22d4ea41ddcf4442d..079e10cf61dbf81ccae6ef8b989ebc16d3db0361 100644 (file)
       sto{s,sb,sw,sd,sq}
       xlat{,b} */
 
+/* "Special" instructions.
+
+   This instruction decoder can decode three special instructions
+   which mean nothing natively (are no-ops as far as regs/mem are
+   concerned) but have meaning for supporting Valgrind.  A special
+   instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
+   48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
+   $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
+   Following that, one of the following 3 are allowed (standard
+   interpretation in parentheses):
+
+      4887DB (xchgq %rbx,%rbx)   %RDX = client_request ( %RAX )
+      4887C9 (xchgq %rcx,%rcx)   %RAX = guest_NRADDR
+      4887D2 (xchgq %rdx,%rdx)   call-noredir *%RAX
+
+   Any other bytes following the 16-byte preamble are illegal and
+   constitute a failure in instruction decoding.  This all assumes
+   that the preamble will never occur except in specific code
+   fragments designed for Valgrind to catch.
+
+   No prefixes may precede a "Special" instruction.  */
+
 /* Translates AMD64 code to IR. */
 
 #include "libvex_basictypes.h"
@@ -398,6 +420,8 @@ static void unimplemented ( HChar* str )
 #define OFFB_TISTART   offsetof(VexGuestAMD64State,guest_TISTART)
 #define OFFB_TILEN     offsetof(VexGuestAMD64State,guest_TILEN)
 
+#define OFFB_NRADDR    offsetof(VexGuestAMD64State,guest_NRADDR)
+
 
 /*------------------------------------------------------------*/
 /*--- Helper bits and pieces for deconstructing the        ---*/
@@ -7949,29 +7973,61 @@ DisResult disInstr_AMD64_WRK (
    if (put_IP)
       stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
 
-   /* Spot the client-request magic sequence. */
+   /* Spot "Special" instructions (see comment at top of file). */
    {
       UChar* code = (UChar*)(guest_code + delta);
-      /* Spot this:
-         C1C01D                roll $29, %eax
-         C1C003                roll $3,  %eax
-         C1C81B                rorl $27, %eax
-         C1C805                rorl $5,  %eax
-         C1C00D                roll $13, %eax
-         C1C013                roll $19, %eax      
+      /* Spot the 16-byte preamble:
+         48C1C703   rolq $3,  %rdi
+         48C1C70D   rolq $13, %rdi
+         48C1C73D   rolq $61, %rdi
+         48C1C733   rolq $51, %rdi
       */
-      if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
-          code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
-          code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
-          code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
-          code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
-          code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
-         ) {
-         DIP("%%edx = client_request ( %%eax )\n");         
-         delta += 18;
-         jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
-         dres.whatNext = Dis_StopHere;
-         goto decode_success;
+      if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7 
+                                               && code[ 3] == 0x03 &&
+          code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7 
+                                               && code[ 7] == 0x0D &&
+          code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7 
+                                               && code[11] == 0x3D &&
+          code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7 
+                                               && code[15] == 0x33) {
+         /* Got a "Special" instruction preamble.  Which one is it? */
+         if (code[16] == 0x48 && code[17] == 0x87 
+                              && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
+            /* %RDX = client_request ( %RAX ) */
+            DIP("%%rdx = client_request ( %%rax )\n");
+            delta += 19;
+            jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
+            dres.whatNext = Dis_StopHere;
+            goto decode_success;
+         }
+         else
+         if (code[16] == 0x48 && code[17] == 0x87 
+                              && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
+            /* %RAX = guest_NRADDR */
+            DIP("%%rax = guest_NRADDR\n");
+            delta += 19;
+            putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
+            goto decode_success;
+         }
+         else
+         if (code[16] == 0x48 && code[17] == 0x87 
+                              && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
+            /* call-noredir *%RAX */
+            DIP("call-noredir *%%rax\n");
+            delta += 19;
+            t1 = newTemp(Ity_I64);
+            assign(t1, getIRegRAX(8));
+            t2 = newTemp(Ity_I64);
+            assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
+            putIReg64(R_RSP, mkexpr(t2));
+            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
+            jmp_treg(Ijk_NoRedir,t1);
+            dres.whatNext = Dis_StopHere;
+            goto decode_success;
+         }
+         /* We don't know what it is. */
+         goto decode_failure;
+         /*NOTREACHED*/
       }
    }
 
index c354762b40e6c747c2b0f26d31e97b57077d7330..290691b74b8a524a3beac7e43de86ee5dbc97bd5 100644 (file)
 __attribute((regparm(2)))
 static UInt genericg_compute_adler32 ( HWord addr, HWord len );
 
+/* Small helpers */
+static Bool const_False ( Addr64 a ) { return False; }
 
-/* Disassemble a complete basic block, starting at guest_IP_bbstart, 
+/* Disassemble a complete basic block, starting at guest_IP_start, 
    returning a new IRBB.  The disassembler may chase across basic
    block boundaries if it wishes and if chase_into_ok allows it.
    The precise guest address ranges from which code has been taken
@@ -71,24 +73,29 @@ static UInt genericg_compute_adler32 ( HWord addr, HWord len );
    do_self_check indicates that the caller needs a self-checking
    translation.
 
-   offB_TIADDR and offB_TILEN are the offsets of guest_TIADDR and
-   guest_TILEN.  Since this routine has to work for any guest state,
-   without knowing what it is, those offsets have to passed in.
-*/
+   do_set_NRADDR indicates that the unredirected guest address for
+   this BB should be written to the guest's NRADDR pseudo-register.
 
-static Bool const_False ( Addr64 a ) { return False; }
+   offB_TIADDR, offB_TILEN and offB_NRADDR are the offsets of
+   guest_TIADDR, guest_TILEN and guest_NRADDR.  Since this routine has
+   to work for any guest state, without knowing what it is, those
+   offsets have to passed in.
+*/
 
 IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
                  /*IN*/ DisOneInstrFn    dis_instr_fn,
                  /*IN*/ UChar*           guest_code,
                  /*IN*/ Addr64           guest_IP_bbstart,
+                 /*IN*/ Addr64           guest_IP_bbstart_noredir,
                  /*IN*/ Bool             (*chase_into_ok)(Addr64),
                  /*IN*/ Bool             host_bigendian,
                  /*IN*/ VexArchInfo*     archinfo_guest,
                  /*IN*/ IRType           guest_word_type,
                  /*IN*/ Bool             do_self_check,
+                 /*IN*/ Bool             do_set_NRADDR,
                  /*IN*/ Int              offB_TISTART,
-                 /*IN*/ Int              offB_TILEN )
+                 /*IN*/ Int              offB_TILEN,
+                 /*IN*/ Int              offB_NRADDR )
 {
    Long       delta;
    Int        i, n_instrs, first_stmt_idx;
@@ -100,6 +107,8 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
    Int        selfcheck_idx = 0;
    IRBB*      irbb;
    Addr64     guest_IP_curr_instr;
+   IRConst*   guest_IP_bbstart_IRConst = NULL;
+   IRConst*   guest_IP_bbstart_noredir_IRConst = NULL;
 
    Bool (*resteerOKfn)(Addr64) = NULL;
 
@@ -131,7 +140,23 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
    delta    = 0;
    n_instrs = 0;
 
-   /* If asked to make a self-checking translation, leave a 5 spaces
+   /* Guest addresses as IRConsts.  Used in the two self-checks
+      generated. */
+   if (do_self_check) {
+      guest_IP_bbstart_IRConst
+         = guest_word_type==Ity_I32 
+              ? IRConst_U32(toUInt(guest_IP_bbstart))
+              : IRConst_U64(guest_IP_bbstart);
+   }
+
+   if (do_set_NRADDR) {
+      guest_IP_bbstart_noredir_IRConst
+         = guest_word_type==Ity_I32 
+              ? IRConst_U32(toUInt(guest_IP_bbstart_noredir))
+              : IRConst_U64(guest_IP_bbstart_noredir);
+   }
+
+   /* If asked to make a self-checking translation, leave 5 spaces
       in which to put the check statements.  We'll fill them in later
       when we know the length and adler32 of the area to check. */
    if (do_self_check) {
@@ -143,6 +168,18 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
       addStmtToIRBB( irbb, IRStmt_NoOp() );
    }
 
+   /* Set guest_NRADDR if asked to.  This records the unredirected
+      guest address of this bb, so that it can later be read (and so
+      used by a function wrapper to get to the function itself. */
+   if (do_set_NRADDR) {
+      /* set guest_NRADDR to guest_IP_bbstart_noredir */
+      addStmtToIRBB( 
+         irbb,
+         IRStmt_Put( offB_NRADDR, 
+                     IRExpr_Const(guest_IP_bbstart_noredir_IRConst))
+      );
+   }
+
    /* Process instructions. */
    while (True) {
       vassert(n_instrs < vex_control.guest_max_insns);
@@ -197,7 +234,7 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
       vassert(dres.whatNext == Dis_StopHere
               || dres.whatNext == Dis_Continue
               || dres.whatNext == Dis_Resteer);
-      vassert(dres.len >= 0 && dres.len <= 18);
+      vassert(dres.len >= 0 && dres.len <= 20);
       if (dres.whatNext != Dis_Resteer)
          vassert(dres.continueAt == 0);
 
@@ -298,7 +335,6 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
    if (do_self_check) {
 
       UInt     len2check, adler32;
-      IRConst* guest_IP_bbstart_IRConst;
       IRTemp   tistart_tmp, tilen_tmp;
 
       vassert(vge->n_used == 1);
@@ -308,11 +344,6 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
 
      adler32 = genericg_compute_adler32( (HWord)guest_code, len2check );
 
-     guest_IP_bbstart_IRConst
-        = guest_word_type==Ity_I32 
-             ? IRConst_U32(toUInt(guest_IP_bbstart))
-             : IRConst_U64(guest_IP_bbstart);
-
      /* Set TISTART and TILEN.  These will describe to the despatcher
         the area of guest code to invalidate should we exit with a
         self-check failure. */
index f30af3de3fe9b5ea7a086f428935432c336781e9..94d2ddef9bffc30b3fbc36361e84e6f01293e4fb 100644 (file)
@@ -154,13 +154,16 @@ IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
                  /*IN*/ DisOneInstrFn    dis_instr_fn,
                  /*IN*/ UChar*           guest_code,
                  /*IN*/ Addr64           guest_IP_bbstart,
+                 /*IN*/ Addr64           guest_IP_bbstart_noredir,
                  /*IN*/ Bool             (*chase_into_ok)(Addr64),
                  /*IN*/ Bool             host_bigendian,
                  /*IN*/ VexArchInfo*     archinfo_guest,
                  /*IN*/ IRType           guest_word_type,
                  /*IN*/ Bool             do_self_check,
+                 /*IN*/ Bool             do_set_NRADDR,
                  /*IN*/ Int              offB_TISTART,
-                 /*IN*/ Int              offB_TILEN );
+                 /*IN*/ Int              offB_TILEN,
+                 /*IN*/ Int              offB_NRADDR );
 
 
 #endif /* ndef GENERIC_BB_TO_IR_H */
index 767381eb2c5507a28e10a16103b8f9e4bf2b7da0..54d176702001fb893829fd105550027638e6529c 100644 (file)
@@ -458,10 +458,12 @@ void LibVEX_GuestPPC32_initialise ( /*OUT*/VexGuestPPC32State* vex_state )
 
    vex_state->guest_EMWARN = EmWarn_NONE;
 
+   vex_state->guest_RESVN   = 0;
+
    vex_state->guest_TISTART = 0;
    vex_state->guest_TILEN   = 0;
 
-   vex_state->guest_RESVN   = 0;
+   vex_state->guest_NRADDR = 0;
 }
 
 
@@ -606,10 +608,12 @@ void LibVEX_GuestPPC64_initialise ( /*OUT*/VexGuestPPC64State* vex_state )
 
    vex_state->guest_EMWARN = EmWarn_NONE;
 
+   vex_state->guest_RESVN   = 0;
+
    vex_state->guest_TISTART = 0;
    vex_state->guest_TILEN   = 0;
 
-   vex_state->guest_RESVN   = 0;
+   vex_state->guest_NRADDR = 0;
 }
 
 
index 4089c803fa1e2b27b4b5bebf7e17e81e143f2c46..3d9b97544dd63bcd30effda4cc0bfe32515cfcf4 100644 (file)
        results would then be zeroed, too.
 */
 
+/* "Special" instructions.
+
+   This instruction decoder can decode three special instructions
+   which mean nothing natively (are no-ops as far as regs/mem are
+   concerned) but have meaning for supporting Valgrind.  A special
+   instruction is flagged by the 16-byte preamble 54001800 54006800
+   5400E800 54009800 (in the standard interpretation, that means:
+   rlwinm 0,0,3,0,0; rlwinm 0,0,13,0,0; rlwinm 0,0,29,0,0; rlwinm
+   0,0,19,0,0).  Following that, one of the following 3 are allowed
+   (standard interpretation in parentheses):
+
+      7C210B78 (or 1,1,1)   %R3 = client_request ( %R4 )
+      7C421378 (or 2,2,2)   %R3 = guest_NRADDR
+      7C631B78 (or 3,3,3)   branch-and-link-to-noredir %R11
+
+   Any other bytes following the 16-byte preamble are illegal and
+   constitute a failure in instruction decoding.  This all assumes
+   that the preamble will never occur except in specific code
+   fragments designed for Valgrind to catch.
+*/
+
 
 /* Translates PPC32/64 code to IR. */
 
@@ -200,7 +221,7 @@ static void* fnptr_to_fnentry( void* f )
 #define OFFB_TISTART    offsetofPPCGuestState(guest_TISTART)
 #define OFFB_TILEN      offsetofPPCGuestState(guest_TILEN)
 #define OFFB_RESVN      offsetofPPCGuestState(guest_RESVN)
-
+#define OFFB_NRADDR     offsetofPPCGuestState(guest_NRADDR)
 
 
 /*------------------------------------------------------------*/
@@ -8358,8 +8379,7 @@ DisResult disInstr_PPC_WRK (
    if (put_IP)
       putGST( PPC_GST_CIA, mkSzImm(ty, guest_CIA_curr_instr) );
 
-   /* Spot the client-request magic sequence. */
-   // Essentially a v. unlikely sequence of noops that we can catch
+   /* Spot "Special" instructions (see comment at top of file). */
    if (mode64) {
       /* Spot the magic sequence, 64-bit mode */
       UChar* code = (UChar*)(&guest_code[delta]);
@@ -8388,31 +8408,54 @@ DisResult disInstr_PPC_WRK (
          goto decode_success;
       }
    } else {
-      /* Spot the magic sequence, 32-bit mode */
-      UChar* code = (UChar*)(&guest_code[delta]);
-
-      /* Spot this:                                       
-         0x7C03D808   tw 0,3,27            => trap word if (0) => nop
-         0x5400E800   rlwinm 0,0,29,0,0    => r0 = rotl(r0,29)
-         0x54001800   rlwinm 0,0, 3,0,0    => r0 = rotl(r0, 3)
-         0x54006800   rlwinm 0,0,13,0,0    => r0 = rotl(r0,13)
-         0x54009800   rlwinm 0,0,19,0,0    => r0 = rotl(r0,19)
-         0x60000000   nop
+      UChar* code = (UChar*)(guest_code + delta);
+      /* Spot the 16-byte preamble:
+         54001800  rlwinm 0,0,3,0,0
+         54006800  rlwinm 0,0,13,0,0
+         5400E800  rlwinm 0,0,29,0,0
+         54009800  rlwinm 0,0,19,0,0
       */
-      if (getUIntBigendianly(code+ 0) == 0x7C03D808 &&
-          getUIntBigendianly(code+ 4) == 0x5400E800 &&
-          getUIntBigendianly(code+ 8) == 0x54001800 &&
-          getUIntBigendianly(code+12) == 0x54006800 &&
-          getUIntBigendianly(code+16) == 0x54009800 &&
-          getUIntBigendianly(code+20) == 0x60000000) {
-         DIP("%%r3 = client_request ( %%r31 )\n");
-         dres.len = 24;
-         delta += 24;
-
-         irbb->next     = mkSzImm( ty, guest_CIA_bbstart + delta );
-         irbb->jumpkind = Ijk_ClientReq;
-         dres.whatNext  = Dis_StopHere;
-         goto decode_success;
+      if (getUIntBigendianly(code+ 0) == 0x54001800 &&
+          getUIntBigendianly(code+ 4) == 0x54006800 &&
+          getUIntBigendianly(code+ 8) == 0x5400E800 &&
+          getUIntBigendianly(code+12) == 0x54009800) {
+         /* Got a "Special" instruction preamble.  Which one is it? */
+         if (getUIntBigendianly(code+16) == 0x7C210B78 /* or 1,1,1 */) {
+            /* %R3 = client_request ( %R4 ) */
+            DIP("r3 = client_request ( %%r4 )\n");
+            delta += 20;
+            irbb->next     = mkSzImm( ty, guest_CIA_bbstart + delta );
+            irbb->jumpkind = Ijk_ClientReq;
+            dres.whatNext  = Dis_StopHere;
+            goto decode_success;
+         }
+         else
+         if (getUIntBigendianly(code+16) == 0x7C421378 /* or 2,2,2 */) {
+            /* %R3 = guest_NRADDR */
+            DIP("r3 = guest_NRADDR\n");
+            delta += 20;
+            dres.len = 20;
+            putIReg(3, IRExpr_Get( OFFB_NRADDR, ty ));
+            goto decode_success;
+         }
+         else
+         if (getUIntBigendianly(code+16) == 0x7C631B78 /* or 3,3,3 */) {
+            /*  branch-and-link-to-noredir %R11 */
+            DIP("branch-and-link-to-noredir r11\n");
+            delta += 20;
+            putGST( PPC_GST_LR, mkSzImm(ty, guest_CIA_bbstart + delta) );
+            irbb->next     = getIReg(11);
+            irbb->jumpkind = Ijk_NoRedir;
+            dres.whatNext  = Dis_StopHere;
+            goto decode_success;
+         }
+         /* We don't know what it is.  Set opc1/opc2 so decode_failure
+            can print the insn following the Special-insn preamble. */
+         theInstr = getUIntBigendianly(code+16);
+         opc1     = ifieldOPC(theInstr);
+         opc2     = ifieldOPClo10(theInstr);
+         goto decode_failure;
+         /*NOTREACHED*/
       }
    }
 
@@ -9007,7 +9050,11 @@ DisResult disInstr_PPC_WRK (
    /* All decode successes end up here. */
    DIP("\n");
 
-   dres.len = 4;
+   if (dres.len == 0) {
+      dres.len = 4;
+   } else {
+      vassert(dres.len == 20);
+   }
    return dres;
 }
 
index 83f05232cabf59cf470ef61e4006baf3ef049f57..9e50b9e2781252afe504e62d2ae53879899b2df6 100644 (file)
@@ -2225,6 +2225,8 @@ void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state )
    /* SSE2 has a 'clflush' cache-line-invalidator which uses these. */
    vex_state->guest_TISTART = 0;
    vex_state->guest_TILEN   = 0;
+
+   vex_state->guest_NRADDR = 0;
 }
 
 
index 762b67d6968e5345a19e71fb8c58a860db29d2c3..38c925eca9c03dfde7a7107599968f70fc3cbba7 100644 (file)
      way through bbs as usual.
 */
 
+/* "Special" instructions.
+
+   This instruction decoder can decode three special instructions
+   which mean nothing natively (are no-ops as far as regs/mem are
+   concerned) but have meaning for supporting Valgrind.  A special
+   instruction is flagged by the 12-byte preamble C1C703 C1C70D C1C71D
+   C1C713 (in the standard interpretation, that means: roll $3, %edi;
+   roll $13, %edi; roll $29, %edi; roll $19, %edi).  Following that,
+   one of the following 3 are allowed (standard interpretation in
+   parentheses):
+
+      87DB (xchgl %ebx,%ebx)   %EDX = client_request ( %EAX )
+      87C9 (xchgl %ecx,%ecx)   %EAX = guest_NRADDR
+      87D2 (xchgl %edx,%edx)   call-noredir *%EAX
+
+   Any other bytes following the 12-byte preamble are illegal and
+   constitute a failure in instruction decoding.  This all assumes
+   that the preamble will never occur except in specific code
+   fragments designed for Valgrind to catch.
+
+   No prefixes may precede a "Special" instruction.
+*/
+
+
 /* Translates x86 code to IR. */
 
 #include "libvex_basictypes.h"
@@ -227,6 +251,8 @@ static IRBB* irbb;
 
 #define OFFB_TISTART   offsetof(VexGuestX86State,guest_TISTART)
 #define OFFB_TILEN     offsetof(VexGuestX86State,guest_TILEN)
+#define OFFB_NRADDR    offsetof(VexGuestX86State,guest_NRADDR)
+
 
 /*------------------------------------------------------------*/
 /*--- Helper bits and pieces for deconstructing the        ---*/
@@ -7012,32 +7038,58 @@ DisResult disInstr_X86_WRK (
    if (put_IP)
       stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
 
-   /* Spot the client-request magic sequence. */
+   /* Spot "Special" instructions (see comment at top of file). */
    {
       UChar* code = (UChar*)(guest_code + delta);
-      /* Spot this:
-         C1C01D                roll $29, %eax
-         C1C003                roll $3,  %eax
-         C1C81B                rorl $27, %eax
-         C1C805                rorl $5,  %eax
-         C1C00D                roll $13, %eax
-         C1C013                roll $19, %eax      
+      /* Spot the 12-byte preamble:
+         C1C703   roll $3,  %edi
+         C1C70D   roll $13, %edi
+         C1C71D   roll $29, %edi
+         C1C713   roll $19, %edi
       */
-      if (code[ 0] == 0xC1 && code[ 1] == 0xC0 && code[ 2] == 0x1D &&
-          code[ 3] == 0xC1 && code[ 4] == 0xC0 && code[ 5] == 0x03 &&
-          code[ 6] == 0xC1 && code[ 7] == 0xC8 && code[ 8] == 0x1B &&
-          code[ 9] == 0xC1 && code[10] == 0xC8 && code[11] == 0x05 &&
-          code[12] == 0xC1 && code[13] == 0xC0 && code[14] == 0x0D &&
-          code[15] == 0xC1 && code[16] == 0xC0 && code[17] == 0x13
-         ) {
-         DIP("%%edx = client_request ( %%eax )\n");         
-         delta += 18;
-         jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
-         dres.whatNext = Dis_StopHere;
-         goto decode_success;
+      if (code[ 0] == 0xC1 && code[ 1] == 0xC7 && code[ 2] == 0x03 &&
+          code[ 3] == 0xC1 && code[ 4] == 0xC7 && code[ 5] == 0x0D &&
+          code[ 6] == 0xC1 && code[ 7] == 0xC7 && code[ 8] == 0x1D &&
+          code[ 9] == 0xC1 && code[10] == 0xC7 && code[11] == 0x13) {
+         /* Got a "Special" instruction preamble.  Which one is it? */
+         if (code[12] == 0x87 && code[13] == 0xDB /* xchgl %ebx,%ebx */) {
+            /* %EDX = client_request ( %EAX ) */
+            DIP("%%edx = client_request ( %%eax )\n");
+            delta += 14;
+            jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
+            dres.whatNext = Dis_StopHere;
+            goto decode_success;
+         }
+         else
+         if (code[12] == 0x87 && code[13] == 0xC9 /* xchgl %ecx,%ecx */) {
+            /* %EAX = guest_NRADDR */
+            DIP("%%eax = guest_NRADDR\n");
+            delta += 14;
+            putIReg(4, R_EAX, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
+            goto decode_success;
+         }
+         else
+         if (code[12] == 0x87 && code[13] == 0xD2 /* xchgl %edx,%edx */) {
+            /* call-noredir *%EAX */
+            DIP("call-noredir *%%eax\n");
+            delta += 14;
+            t1 = newTemp(Ity_I32);
+            assign(t1, getIReg(4,R_EAX));
+            t2 = newTemp(Ity_I32);
+            assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
+            putIReg(4, R_ESP, mkexpr(t2));
+            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta));
+            jmp_treg(Ijk_NoRedir,t1);
+            dres.whatNext = Dis_StopHere;
+            goto decode_success;
+         }
+         /* We don't know what it is. */
+         goto decode_failure;
+         /*NOTREACHED*/
       }
    }
 
+   /* Deal with prefixes. */
    /* Skip a LOCK prefix. */
    /* 2005 Jan 06: the following insns are observed to sometimes
       have a LOCK prefix:
index acc5a116df495100d07ed7aeb52cecf46f59e31d..44fa0c573a6fd07252acc8c5b3b461ad8d7ef679 100644 (file)
@@ -2620,6 +2620,9 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i,
          case Ijk_TInval:
             *p++ = 0xBD;
             p = emit32(p, VEX_TRC_JMP_TINVAL); break;
+         case Ijk_NoRedir:
+            *p++ = 0xBD;
+            p = emit32(p, VEX_TRC_JMP_NOREDIR); break;
          case Ijk_Ret:
          case Ijk_Call:
          case Ijk_Boring:
index e707be28182ecb0212038269657a66d81fa96efa..066ba2631f57fab4d57c992a947351865f0029ba 100644 (file)
@@ -2942,6 +2942,7 @@ Int emit_PPCInstr ( UChar* buf, Int nbuf, PPCInstr* i,
          case Ijk_MapFail:     trc = VEX_TRC_JMP_MAPFAIL;     break;
          case Ijk_NoDecode:    trc = VEX_TRC_JMP_NODECODE;    break;
          case Ijk_TInval:      trc = VEX_TRC_JMP_TINVAL;      break;
+         case Ijk_NoRedir:     trc = VEX_TRC_JMP_NOREDIR;     break;
          case Ijk_Ret:
          case Ijk_Call:
          case Ijk_Boring:
index f1a67b8fc69c55239ceb054fd2143e1ff8cacbfe..a53a8c2a75fb3ba2edcb5667a8359709db93c46a 100644 (file)
@@ -2179,6 +2179,9 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i,
          case Ijk_TInval:
             *p++ = 0xBD;
             p = emit32(p, VEX_TRC_JMP_TINVAL); break;
+         case Ijk_NoRedir:
+            *p++ = 0xBD;
+            p = emit32(p, VEX_TRC_JMP_NOREDIR); break;
          case Ijk_Sys_sysenter:
             *p++ = 0xBD;
             p = emit32(p, VEX_TRC_JMP_SYS_SYSENTER); break;
index a6490525931120a7bff4baf17d61cf5092e8d024..c04b7da4a51f2b59a020ae9f5117f86eb8ceba06 100644 (file)
@@ -684,6 +684,7 @@ void ppIRJumpKind ( IRJumpKind kind )
       case Ijk_NoDecode:     vex_printf("NoDecode"); break;
       case Ijk_MapFail:      vex_printf("MapFail"); break;
       case Ijk_TInval:       vex_printf("Invalidate"); break;
+      case Ijk_NoRedir:      vex_printf("NoRedir"); break;
       case Ijk_Sys_syscall:  vex_printf("Sys_syscall"); break;
       case Ijk_Sys_int32:    vex_printf("Sys_int32"); break;
       case Ijk_Sys_int128:   vex_printf("Sys_int128"); break;
index b649bb04db31da6fbad4e9985bb676210ba6adda..a2986d3ac5155c0c977e7ad21c77517f2778e4fc 100644 (file)
@@ -200,7 +200,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
    HInstrArray*    vcode;
    HInstrArray*    rcode;
    Int             i, j, k, out_used, guest_sizeB;
-   Int             offB_TISTART, offB_TILEN;
+   Int             offB_TISTART, offB_TILEN, offB_NRADDR;
    UChar           insn_bytes[32];
    IRType          guest_word_type;
    IRType          host_word_type;
@@ -226,6 +226,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
    offB_TISTART           = 0;
    offB_TILEN             = 0;
    mode64                 = False;
+   offB_NRADDR            = 0;
 
    vex_traceflags = vta->traceflags;
 
@@ -335,12 +336,14 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          guest_layout     = &x86guest_layout;
          offB_TISTART     = offsetof(VexGuestX86State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestX86State,guest_TILEN);
+         offB_NRADDR      = offsetof(VexGuestX86State,guest_NRADDR);
          vassert(vta->archinfo_guest.subarch == VexSubArchX86_sse0
                  || vta->archinfo_guest.subarch == VexSubArchX86_sse1
                  || vta->archinfo_guest.subarch == VexSubArchX86_sse2);
          vassert(0 == sizeof(VexGuestX86State) % 8);
-         vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART ) == 4);
-         vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN ) == 4);
+         vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART) == 4);
+         vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN  ) == 4);
+         vassert(sizeof( ((VexGuestX86State*)0)->guest_NRADDR ) == 4);
          break;
 
       case VexArchAMD64:
@@ -352,10 +355,12 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          guest_layout     = &amd64guest_layout;
          offB_TISTART     = offsetof(VexGuestAMD64State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestAMD64State,guest_TILEN);
+         offB_NRADDR      = offsetof(VexGuestAMD64State,guest_NRADDR);
          vassert(vta->archinfo_guest.subarch == VexSubArch_NONE);
          vassert(0 == sizeof(VexGuestAMD64State) % 8);
          vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TISTART ) == 8);
-         vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN ) == 8);
+         vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN   ) == 8);
+         vassert(sizeof( ((VexGuestAMD64State*)0)->guest_NRADDR  ) == 8);
          break;
 
       case VexArchARM:
@@ -367,6 +372,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          guest_layout     = &armGuest_layout;
          offB_TISTART     = 0; /* hack ... arm has bitrot */
          offB_TILEN       = 0; /* hack ... arm has bitrot */
+         offB_NRADDR      = 0; /* hack ... arm has bitrot */
          vassert(vta->archinfo_guest.subarch == VexSubArchARM_v4);
          break;
 
@@ -379,12 +385,14 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          guest_layout     = &ppc32Guest_layout;
          offB_TISTART     = offsetof(VexGuestPPC32State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestPPC32State,guest_TILEN);
+         offB_NRADDR      = offsetof(VexGuestPPC32State,guest_NRADDR);
          vassert(vta->archinfo_guest.subarch == VexSubArchPPC32_I
                  || vta->archinfo_guest.subarch == VexSubArchPPC32_FI
                  || vta->archinfo_guest.subarch == VexSubArchPPC32_VFI);
          vassert(0 == sizeof(VexGuestPPC32State) % 8);
          vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TISTART ) == 4);
-         vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN ) == 4);
+         vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN   ) == 4);
+         vassert(sizeof( ((VexGuestPPC32State*)0)->guest_NRADDR  ) == 4);
          break;
 
       case VexArchPPC64:
@@ -426,13 +434,16 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
                      disInstrFn,
                      vta->guest_bytes, 
                      vta->guest_bytes_addr,
+                     vta->guest_bytes_addr_noredir,
                      vta->chase_into_ok,
                      host_is_bigendian,
                      &vta->archinfo_guest,
                      guest_word_type,
                      vta->do_self_check,
+                     vta->do_set_NRADDR,
                      offB_TISTART,
-                     offB_TILEN );
+                     offB_TILEN,
+                     offB_NRADDR );
 
    vexAllocSanityCheck();
 
index 5fb9718cca7dc5478ccd0509f5eeb9108dd72ae6..73eeb2bf132d26d383d5be3407981115204dfb9a 100644 (file)
@@ -345,6 +345,9 @@ typedef
 
       /* IN: should this translation be self-checking?  default: False */
       Bool    do_self_check;
+      /* IN: should this translation set guest_NRADDR? */
+      Bool    do_set_NRADDR;
+
       /* IN: debug: trace vex activity at various points */
       Int     traceflags;
 
@@ -383,7 +386,6 @@ typedef
 extern 
 VexTranslateResult LibVEX_Translate ( VexTranslateArgs* );
 
-
 /* A subtlety re interaction between self-checking translations and
    bb-chasing.  The supplied chase_into_ok function should say NO
    (False) when presented with any address for which you might want to
@@ -456,11 +458,19 @@ extern void LibVEX_ShowStats ( void );
 
    ALL GUEST ARCHITECTURES
    ~~~~~~~~~~~~~~~~~~~~~~~
-   The architecture must contain two pseudo-registers, guest_TISTART
+   The guest state must contain two pseudo-registers, guest_TISTART
    and guest_TILEN.  These are used to pass the address of areas of
    guest code, translations of which are to be invalidated, back to
    the despatcher.  Both pseudo-regs must have size equal to the guest
    word size.
+
+   The architecture must a third pseudo-register, guest_NRADDR, also
+   guest-word-sized.  This is used to record the unredirected guest
+   address at the start of a translation whose start has been
+   redirected.  By reading this pseudo-register shortly afterwards,
+   the translation can find out what the corresponding no-redirection
+   address was.  Note, this is only set for wrap-style redirects, not
+   for replace-style ones.
 */
 #endif /* ndef __LIBVEX_H */
 
index 88c83547d7bcef896d90127df3213939d0586757..785e3560b526b258be756c6957c759e2b24894d0 100644 (file)
@@ -145,6 +145,14 @@ typedef
       ULong guest_TISTART;
       ULong guest_TILEN;
 
+      /* Used to record the unredirected guest address at the start of
+         a translation whose start has been redirected.  By reading
+         this pseudo-register shortly afterwards, the translation can
+         find out what the corresponding no-redirection address was.
+         Note, this is only set for wrap-style redirects, not for
+         replace-style ones. */
+      ULong guest_NRADDR;
+
       /* Padding to make it have an 8-aligned size */
       /* UInt   padding; */
    }
index b9df3569cd555dfa49b6cac7ba82b70e0f3878be..7fc41f631e3036271d3d8137bccc61c71e2f970f 100644 (file)
@@ -199,13 +199,21 @@ typedef
       /* Emulation warnings */
       /* 940 */ UInt guest_EMWARN;
 
-      /* For icbi: record start and length of area to invalidate */
-      /* 944 */ UInt guest_TISTART;
-      /* 948 */ UInt guest_TILEN;
-
       /* For lwarx/stwcx.: 0 == no reservation exists, non-0 == a
          reservation exists. */
-      /* 952 */ UInt guest_RESVN;
+      /* 944 */ UInt guest_RESVN;
+
+      /* For icbi: record start and length of area to invalidate */
+      /* 948 */ UInt guest_TISTART;
+      /* 952 */ UInt guest_TILEN;
+
+      /* Used to record the unredirected guest address at the start of
+         a translation whose start has been redirected.  By reading
+         this pseudo-register shortly afterwards, the translation can
+         find out what the corresponding no-redirection address was.
+         Note, this is only set for wrap-style redirects, not for
+         replace-style ones. */
+      /* 956 */ UInt guest_NRADDR;
 
       /* Padding to make it have an 8-aligned size */
       /* 956 */ UInt  padding;
index c03b74bf0628e8766954a73b79d7bd09bdc43670..eee7094e2a81bdd26c5b8392a6e8924391ca27f6 100644 (file)
@@ -248,9 +248,16 @@ typedef
          reservation exists. */
       /* 1104 */ ULong guest_RESVN;
 
-      /* Padding to make it have an 16-aligned size */
-      /* 1112 */ ULong padding2;
-      /* 1120 */
+      /* Used to record the unredirected guest address at the start of
+         a translation whose start has been redirected.  By reading
+         this pseudo-register shortly afterwards, the translation can
+         find out what the corresponding no-redirection address was.
+         Note, this is only set for wrap-style redirects, not for
+         replace-style ones. */
+      /* 1112 */ ULong guest_NRADDR;
+
+      /* Padding to make it have an 8-aligned size */
+      /* UInt  padding; */
    }
    VexGuestPPC64State;
 
index fd98627592c6d0718c839346e5c3fcb157f89c5b..e78afd3bda0766c4de8509dd35fb2c03093c8136 100644 (file)
@@ -208,18 +208,20 @@ typedef
       /* Emulation warnings */
       UInt   guest_EMWARN;
 
-      /* Translation-invalidation area description.  Not used on x86
-         (there is no invalidate-icache insn), but needed so as to
-         allow users of the library to uniformly assume that the guest
-         state contains these two fields -- otherwise there is
-         compilation breakage.  On x86, these two fields are set to
-         zero by LibVEX_GuestX86_initialise and then should be ignored
-         forever thereafter. */
+      /* For clflush: record start and length of area to invalidate */
       UInt guest_TISTART;
       UInt guest_TILEN;
 
+      /* Used to record the unredirected guest address at the start of
+         a translation whose start has been redirected.  By reading
+         this pseudo-register shortly afterwards, the translation can
+         find out what the corresponding no-redirection address was.
+         Note, this is only set for wrap-style redirects, not for
+         replace-style ones. */
+      UInt guest_NRADDR;
+
       /* Padding to make it have an 8-aligned size */
-      /* UInt   padding; */
+      UInt padding;
    }
    VexGuestX86State;
 
index e9cf28e2aa691dd78487269fd6d35072d381f9d7..130a4fe13edeb93b84b9348612e2ce65636ec2b3 100644 (file)
@@ -855,6 +855,7 @@ typedef
       Ijk_NoDecode,       /* next instruction cannot be decoded */
       Ijk_MapFail,        /* Vex-provided address translation failed */
       Ijk_TInval,         /* Invalidate translations before continuing. */
+      Ijk_NoRedir,        /* Jump to un-redirected guest addr */
       /* Unfortunately, various guest-dependent syscall kinds.  They
         all mean: do a syscall before continuing. */
       Ijk_Sys_syscall,    /* amd64 'syscall', ppc 'sc' */
index 757ceead25a8b9c003acbf4e4149aa4a9c74f063..ccba4e3cbffdf1ee35d54909762b0c03da2a3344 100644 (file)
@@ -58,6 +58,7 @@
 
 #define VEX_TRC_JMP_TINVAL     61  /* invalidate translations before
                                       continuing */
+#define VEX_TRC_JMP_NOREDIR    81  /* jump to undirected guest addr */
 #define VEX_TRC_JMP_EMWARN     63  /* deliver emulation warning before
                                       continuing */
 #define VEX_TRC_JMP_CLIENTREQ  65  /* do a client req before continuing */
index a2a63aac41805360b8706d90b58d03ead611db75..ddc0bb14b98af018767d0660ed8cfc2387ea7075 100644 (file)
@@ -174,6 +174,7 @@ int main ( int argc, char** argv )
       vta.instrument2     = NULL;
 #endif
       vta.do_self_check   = False;
+      vta.do_set_NRADDR   = False;
       vta.traceflags      = TEST_FLAGS;
 #if 1 /* x86, amd64 hosts */
       vta.dispatch        = (void*)0x12345678;