Two different sets of changes (hard to disentangle):

* Remove from Vex all knowledge about function wrapping.  All the IR
  trickery needed can be done on the Valgrind side, by giving
  LibVEX_Translate yet another callback.  This one is called just
  before any instructions are disassembled into IR, allowing Valgrind
  to insert its own IR preamble if it wants.  It also allows Valgrind
  to inhibit any insn disassembly for the block.  Effect is that this
  allows Valgrind to provide any old IR for a given translation, and
  have Vex process it as usual, yet that IR can be anything and does
  not have to bear any relationship to any guest insns anywhere.

* Consistently pass a void* closure argument as the first parameter to
  all Valgrind-supplied callbacks.  This gets rid of various nasty hacks
  at the Valgrind side to do with passing instance-specific values
  to callbacks.



git-svn-id: svn://svn.valgrind.org/vex/trunk@1540 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-amd64/gdefs.h b/priv/guest-amd64/gdefs.h
index 7d2e9f6..cae5142 100644
--- a/priv/guest-amd64/gdefs.h
+++ b/priv/guest-amd64/gdefs.h
@@ -59,7 +59,8 @@
 extern
 DisResult disInstr_AMD64 ( IRBB*        irbb,
                            Bool         put_IP,
-                           Bool         (*resteerOkFn) ( Addr64 ),
+                           Bool         (*resteerOkFn) ( void*, Addr64 ),
+                           void*        callback_opaque,
                            UChar*       guest_code,
                            Long         delta,
                            Addr64       guest_IP,
diff --git a/priv/guest-amd64/toIR.c b/priv/guest-amd64/toIR.c
index 079e10c..6dcee7b 100644
--- a/priv/guest-amd64/toIR.c
+++ b/priv/guest-amd64/toIR.c
@@ -7927,7 +7927,8 @@
 static
 DisResult disInstr_AMD64_WRK ( 
              Bool         put_IP,
-             Bool         (*resteerOkFn) ( Addr64 ),
+             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo 
           )
@@ -11543,7 +11544,7 @@
       putIReg64(R_RSP, mkexpr(t1));
       storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
       make_redzone_AbiHint(t1, "call-d32");
-      if (resteerOkFn((Addr64)d64)) {
+      if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
          /* follow into the call target. */
          dres.whatNext   = Dis_Resteer;
          dres.continueAt = d64;
@@ -11755,7 +11756,7 @@
          goto decode_failure; /* JRS added 2004 July 11 */
       d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); 
       delta++;
-      if (resteerOkFn(d64)) {
+      if (resteerOkFn(callback_opaque,d64)) {
          dres.whatNext   = Dis_Resteer;
          dres.continueAt = d64;
       } else {
@@ -11771,7 +11772,7 @@
          goto decode_failure; /* JRS added 2004 July 11 */
       d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
-      if (resteerOkFn(d64)) {
+      if (resteerOkFn(callback_opaque,d64)) {
          dres.whatNext   = Dis_Resteer;
          dres.continueAt = d64;
       } else {
@@ -13639,7 +13640,8 @@
 
 DisResult disInstr_AMD64 ( IRBB*        irbb_IN,
                            Bool         put_IP,
-                           Bool         (*resteerOkFn) ( Addr64 ),
+                           Bool         (*resteerOkFn) ( void*, Addr64 ),
+                           void*        callback_opaque,
                            UChar*       guest_code_IN,
                            Long         delta,
                            Addr64       guest_IP,
@@ -13659,7 +13661,7 @@
    guest_RIP_next_assumed   = 0;
    guest_RIP_next_mustcheck = False;
 
-   dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn,
+   dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn, callback_opaque,
                                delta, archinfo );
 
    /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
diff --git a/priv/guest-generic/bb_to_IR.c b/priv/guest-generic/bb_to_IR.c
index 290691b..ca3d9f9 100644
--- a/priv/guest-generic/bb_to_IR.c
+++ b/priv/guest-generic/bb_to_IR.c
@@ -57,7 +57,9 @@
 static UInt genericg_compute_adler32 ( HWord addr, HWord len );
 
 /* Small helpers */
-static Bool const_False ( Addr64 a ) { return False; }
+static Bool const_False ( void* callback_opaque, Addr64 a ) { 
+   return False; 
+}
 
 /* Disassemble a complete basic block, starting at guest_IP_start, 
    returning a new IRBB.  The disassembler may chase across basic
@@ -73,29 +75,36 @@
    do_self_check indicates that the caller needs a self-checking
    translation.
 
-   do_set_NRADDR indicates that the unredirected guest address for
-   this BB should be written to the guest's NRADDR pseudo-register.
+   preamble_function is a callback which allows the caller to add
+   its own IR preamble (following the self-check, if any).  May be
+   NULL.  If non-NULL, the IRBB under construction is handed to 
+   this function, which presumably adds IR statements to it.  The
+   callback may optionally complete the block and direct bb_to_IR
+   not to disassemble any instructions into it; this is indicated
+   by the callback returning True.
 
-   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.
+   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.
+
+   callback_opaque is a caller-supplied pointer to data which the
+   callbacks may want to see.  Vex has no idea what it is.
+   (In fact it's a VgInstrumentClosure.)
 */
 
 IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
+                 /*IN*/ void*            callback_opaque,
                  /*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             (*chase_into_ok)(void*,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*/ Bool             (*preamble_function)(void*,IRBB*),
                  /*IN*/ Int              offB_TISTART,
-                 /*IN*/ Int              offB_TILEN,
-                 /*IN*/ Int              offB_NRADDR )
+                 /*IN*/ Int              offB_TILEN )
 {
    Long       delta;
    Int        i, n_instrs, first_stmt_idx;
@@ -108,9 +117,8 @@
    IRBB*      irbb;
    Addr64     guest_IP_curr_instr;
    IRConst*   guest_IP_bbstart_IRConst = NULL;
-   IRConst*   guest_IP_bbstart_noredir_IRConst = NULL;
 
-   Bool (*resteerOKfn)(Addr64) = NULL;
+   Bool (*resteerOKfn)(void*,Addr64) = NULL;
 
    debug_print = toBool(vex_traceflags & VEX_TRACE_FE);
 
@@ -149,13 +157,6 @@
               : 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. */
@@ -168,16 +169,18 @@
       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))
-      );
+   /* If the caller supplied a function to add its own preamble, use
+      it now. */
+   if (preamble_function) {
+      Bool stopNow = preamble_function( callback_opaque, irbb );
+      if (stopNow) {
+         /* The callback has completed the IR block without any guest
+            insns being disassembled into it, so just return it at
+            this point, even if a self-check was requested - as there
+            is nothing to self-check.  The five self-check no-ops will
+            still be in place, but they are harmless. */
+         return irbb;
+      }
    }
 
    /* Process instructions. */
@@ -224,6 +227,7 @@
       dres = dis_instr_fn ( irbb,
                             need_to_put_IP,
                             resteerOKfn,
+                            callback_opaque,
                             guest_code,
                             delta,
                             guest_IP_curr_instr,
@@ -308,7 +312,7 @@
             vassert(resteerOK);
             vassert(irbb->next == NULL);
             /* figure out a new delta to continue at. */
-            vassert(resteerOKfn(dres.continueAt));
+            vassert(resteerOKfn(callback_opaque,dres.continueAt));
             delta = dres.continueAt - guest_IP_bbstart;
             /* we now have to start a new extent slot. */
             vge->n_used++;
diff --git a/priv/guest-generic/bb_to_IR.h b/priv/guest-generic/bb_to_IR.h
index 94d2dde..04af2eb 100644
--- a/priv/guest-generic/bb_to_IR.h
+++ b/priv/guest-generic/bb_to_IR.h
@@ -124,7 +124,11 @@
       /*IN*/  Bool         put_IP,
 
       /* Return True iff resteering to the given addr is allowed */
-      /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
+      /*IN*/  Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+
+      /* Vex-opaque data passed to all caller (valgrind) supplied
+         callbacks. */
+      /*IN*/  void*        callback_opaque,
 
       /* Where is the guest code? */
       /*IN*/  UChar*       guest_code,
@@ -151,19 +155,18 @@
 /* See detailed comment in bb_to_IR.c. */
 extern
 IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
+                 /*IN*/ void*            closure_opaque,
                  /*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             (*chase_into_ok)(void*,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*/ Bool             (*preamble_function)(void*,IRBB*),
                  /*IN*/ Int              offB_TISTART,
-                 /*IN*/ Int              offB_TILEN,
-                 /*IN*/ Int              offB_NRADDR );
+                 /*IN*/ Int              offB_TILEN );
 
 
 #endif /* ndef GENERIC_BB_TO_IR_H */
diff --git a/priv/guest-ppc/gdefs.h b/priv/guest-ppc/gdefs.h
index c77dccd..d427f93 100644
--- a/priv/guest-ppc/gdefs.h
+++ b/priv/guest-ppc/gdefs.h
@@ -60,7 +60,8 @@
 extern
 DisResult disInstr_PPC ( IRBB*        irbb,
                          Bool         put_IP,
-                         Bool         (*resteerOkFn) ( Addr64 ),
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         void*        callback_opaque,
                          UChar*       guest_code,
                          Long         delta,
                          Addr64       guest_IP,
diff --git a/priv/guest-ppc/toIR.c b/priv/guest-ppc/toIR.c
index dafbffc..7e7cc5b 100644
--- a/priv/guest-ppc/toIR.c
+++ b/priv/guest-ppc/toIR.c
@@ -358,7 +358,7 @@
    vassert(begin < 32);
    vassert(end < 32);
    UInt m1 = ((UInt)(-1)) << begin;
-   UInt m2 = ((UInt)(-1)) << (end + 1);
+   UInt m2 = ((UInt)(-1)) << end << 1;
    UInt mask = m1 ^ m2;
    if (begin > end) mask = ~mask;  // wrap mask
    return mask;
@@ -370,7 +370,7 @@
    vassert(begin < 64);
    vassert(end < 64);
    ULong m1 = ((ULong)(-1)) << begin;
-   ULong m2 = ((ULong)(-1)) << (end + 1);
+   ULong m2 = ((ULong)(-1)) << end << 1;
    ULong mask = m1 ^ m2;
    if (begin > end) mask = ~mask;  // wrap mask
    return mask;
@@ -4144,7 +4144,8 @@
 */
 static Bool dis_branch ( UInt theInstr, 
                          /*OUT*/DisResult* dres,
-                         Bool (*resteerOkFn)(Addr64) )
+                         Bool (*resteerOkFn)(void*,Addr64),
+                         void* callback_opaque )
 {
    UChar opc1    = ifieldOPC(theInstr);
    UChar BO      = ifieldRegDS(theInstr);
@@ -4195,7 +4196,7 @@
       if (flag_LK)
          putGST( PPC_GST_LR, e_nia );
 
-      if (resteerOkFn(tgt)) {
+      if (resteerOkFn( callback_opaque, tgt )) {
          dres->whatNext   = Dis_Resteer;
          dres->continueAt = tgt;
       } else {
@@ -8341,7 +8342,8 @@
 static   
 DisResult disInstr_PPC_WRK ( 
              Bool         put_IP,
-             Bool         (*resteerOkFn) ( Addr64 ),
+             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo 
           )
@@ -8498,7 +8500,8 @@
 
    /* Branch Instructions */
    case 0x12: case 0x10: // b, bc
-      if (dis_branch(theInstr, &dres, resteerOkFn)) goto decode_success;
+      if (dis_branch(theInstr, &dres, resteerOkFn, callback_opaque)) 
+         goto decode_success;
       goto decode_failure;
 
    /* System Linkage Instructions */
@@ -8644,7 +8647,8 @@
          
       /* Branch Instructions */
       case 0x210: case 0x010: // bcctr, bclr
-         if (dis_branch(theInstr, &dres, resteerOkFn)) goto decode_success;
+         if (dis_branch(theInstr, &dres, resteerOkFn, callback_opaque)) 
+            goto decode_success;
          goto decode_failure;
          
       /* Memory Synchronization Instructions */
@@ -9057,7 +9061,8 @@
 
 DisResult disInstr_PPC ( IRBB*        irbb_IN,
                          Bool         put_IP,
-                         Bool         (*resteerOkFn) ( Addr64 ),
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         void*        callback_opaque,
                          UChar*       guest_code_IN,
                          Long         delta,
                          Addr64       guest_IP,
@@ -9093,7 +9098,7 @@
    guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
    guest_CIA_bbstart    = mkSzAddr(ty, guest_IP - delta);
 
-   dres = disInstr_PPC_WRK ( put_IP, resteerOkFn,
+   dres = disInstr_PPC_WRK ( put_IP, resteerOkFn, callback_opaque,
                              delta, archinfo );
 
    return dres;
diff --git a/priv/guest-x86/gdefs.h b/priv/guest-x86/gdefs.h
index 235befc..d41b5ff 100644
--- a/priv/guest-x86/gdefs.h
+++ b/priv/guest-x86/gdefs.h
@@ -59,7 +59,8 @@
 extern
 DisResult disInstr_X86 ( IRBB*        irbb,
                          Bool         put_IP,
-                         Bool         (*resteerOkFn) ( Addr64 ),
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         void*        callback_opaque,
                          UChar*       guest_code,
                          Long         delta,
                          Addr64       guest_IP,
diff --git a/priv/guest-x86/toIR.c b/priv/guest-x86/toIR.c
index 38c925e..08cc5de 100644
--- a/priv/guest-x86/toIR.c
+++ b/priv/guest-x86/toIR.c
@@ -6994,7 +6994,8 @@
 static
 DisResult disInstr_X86_WRK ( 
              Bool         put_IP,
-             Bool         (*resteerOkFn) ( Addr64 ),
+             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo 
           )
@@ -10586,7 +10587,7 @@
          assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
          putIReg(4, R_ESP, mkexpr(t1));
          storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
-         if (resteerOkFn((Addr64)(Addr32)d32)) {
+         if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
             /* follow into the call target. */
             dres.whatNext   = Dis_Resteer;
             dres.continueAt = (Addr64)(Addr32)d32;
@@ -10807,7 +10808,7 @@
    case 0xEB: /* Jb (jump, byte offset) */
       d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta); 
       delta++;
-      if (resteerOkFn((Addr64)(Addr32)d32)) {
+      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
          dres.whatNext   = Dis_Resteer;
          dres.continueAt = (Addr64)(Addr32)d32;
       } else {
@@ -10821,7 +10822,7 @@
       vassert(sz == 4); /* JRS added 2004 July 11 */
       d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
-      if (resteerOkFn((Addr64)(Addr32)d32)) {
+      if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
          dres.whatNext   = Dis_Resteer;
          dres.continueAt = (Addr64)(Addr32)d32;
       } else {
@@ -10849,7 +10850,7 @@
    case 0x7F: /* JGb/JNLEb (jump greater) */
       d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta); 
       delta++;
-      if (0 && resteerOkFn((Addr64)(Addr32)d32)) {
+      if (0 && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
          /* Unused experimental hack: speculatively follow one arm
             of a conditional branch. */
          /* Assume the branch is taken.  So we need to emit a
@@ -12574,7 +12575,8 @@
 
 DisResult disInstr_X86 ( IRBB*        irbb_IN,
                          Bool         put_IP,
-                         Bool         (*resteerOkFn) ( Addr64 ),
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         void*        callback_opaque,
                          UChar*       guest_code_IN,
                          Long         delta,
                          Addr64       guest_IP,
@@ -12590,7 +12592,7 @@
    guest_EIP_curr_instr = (Addr32)guest_IP;
    guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
 
-   dres = disInstr_X86_WRK ( put_IP, resteerOkFn,
+   dres = disInstr_X86_WRK ( put_IP, resteerOkFn, callback_opaque,
                              delta, archinfo );
 
    return dres;
diff --git a/priv/main/vex_main.c b/priv/main/vex_main.c
index a2986d3..311f284 100644
--- a/priv/main/vex_main.c
+++ b/priv/main/vex_main.c
@@ -200,7 +200,7 @@
    HInstrArray*    vcode;
    HInstrArray*    rcode;
    Int             i, j, k, out_used, guest_sizeB;
-   Int             offB_TISTART, offB_TILEN, offB_NRADDR;
+   Int             offB_TISTART, offB_TILEN;
    UChar           insn_bytes[32];
    IRType          guest_word_type;
    IRType          host_word_type;
@@ -226,7 +226,6 @@
    offB_TISTART           = 0;
    offB_TILEN             = 0;
    mode64                 = False;
-   offB_NRADDR            = 0;
 
    vex_traceflags = vta->traceflags;
 
@@ -336,7 +335,6 @@
          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);
@@ -355,7 +353,6 @@
          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);
@@ -372,7 +369,6 @@
          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;
 
@@ -385,7 +381,6 @@
          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);
@@ -408,7 +403,8 @@
                  || vta->archinfo_guest.subarch == VexSubArchPPC64_VFI);
          vassert(0 == sizeof(VexGuestPPC64State) % 16);
          vassert(sizeof( ((VexGuestPPC64State*)0)->guest_TISTART ) == 8);
-         vassert(sizeof( ((VexGuestPPC64State*)0)->guest_TILEN ) == 8);
+         vassert(sizeof( ((VexGuestPPC64State*)0)->guest_TILEN   ) == 8);
+         vassert(sizeof( ((VexGuestPPC64State*)0)->guest_NRADDR  ) == 8);
          break;
 
       default:
@@ -431,19 +427,18 @@
                    "------------------------\n\n");
 
    irbb = bb_to_IR ( vta->guest_extents,
+                     vta->callback_opaque,
                      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,
+                     vta->preamble_function,
                      offB_TISTART,
-                     offB_TILEN,
-                     offB_NRADDR );
+                     offB_TILEN );
 
    vexAllocSanityCheck();
 
@@ -499,15 +494,15 @@
 
    /* Get the thing instrumented. */
    if (vta->instrument1)
-      irbb = vta->instrument1(irbb, guest_layout, 
-                              vta->guest_bytes_addr_noredir,
+      irbb = vta->instrument1(vta->callback_opaque,
+                              irbb, guest_layout, 
                               vta->guest_extents,
                               guest_word_type, host_word_type);
    vexAllocSanityCheck();
 
    if (vta->instrument2)
-      irbb = vta->instrument2(irbb, guest_layout,
-                              vta->guest_bytes_addr_noredir, 
+      irbb = vta->instrument2(vta->callback_opaque,
+                              irbb, guest_layout,
                               vta->guest_extents,
                               guest_word_type, host_word_type);
       
diff --git a/pub/libvex.h b/pub/libvex.h
index 73eeb2b..5dfc5a6 100644
--- a/pub/libvex.h
+++ b/pub/libvex.h
@@ -310,20 +310,23 @@
       VexArch      arch_host;
       VexArchInfo  archinfo_host;
 
+      /* IN: an opaque value which is passed as the first arg to all
+         callback functions supplied in this struct.  Vex has no idea
+         what's at the other end of this pointer. */
+      void*   callback_opaque;
+
       /* IN: the block to translate, and its guest address. */
       /* where are the actual bytes in the host's address space? */
       UChar*  guest_bytes;
       /* where do the bytes really come from in the guest's aspace?
-         This is the post-redirection guest address. */
+         This is the post-redirection guest address.  Not that Vex
+         understands anything about redirection; that is all done on
+         the Valgrind side. */
       Addr64  guest_bytes_addr;
-      /* where do the bytes claim to come from in the guest address
-         space?  (what guest entry point address do they correspond
-         to?)  This is the pre-redirection guest address. */
-      Addr64  guest_bytes_addr_noredir;
 
       /* Is it OK to chase into this guest address?  May not be
 	 NULL. */
-      Bool    (*chase_into_ok) ( Addr64 );
+      Bool    (*chase_into_ok) ( /*callback_opaque*/void*, Addr64 );
 
       /* OUT: which bits of guest code actually got translated */
       VexGuestExtents* guest_extents;
@@ -336,17 +339,30 @@
 
       /* IN: optionally, two instrumentation functions.  May be
 	 NULL. */
-      IRBB*   (*instrument1) ( IRBB*, VexGuestLayout*, 
-                               Addr64, VexGuestExtents*,
+      IRBB*   (*instrument1) ( /*callback_opaque*/void*, 
+                               IRBB*, 
+                               VexGuestLayout*, 
+                               VexGuestExtents*,
                                IRType gWordTy, IRType hWordTy );
-      IRBB*   (*instrument2) ( IRBB*, VexGuestLayout*, 
-                               Addr64, VexGuestExtents*,
+      IRBB*   (*instrument2) ( /*callback_opaque*/void*, 
+                               IRBB*, 
+                               VexGuestLayout*, 
+                               VexGuestExtents*,
                                IRType gWordTy, IRType hWordTy );
 
       /* 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: optionally, a callback which allows the caller to add its
+         own IR preamble following the self-check and any other
+         VEX-generated preamble, if any.  May be NULL.  If non-NULL,
+         the IRBB under construction is handed to this function, which
+         presumably adds IR statements to it.  The callback may
+         optionally complete the block and direct bb_to_IR not to
+         disassemble any instructions into it; this is indicated by
+         the callback returning True.
+      */
+      Bool    (*preamble_function)(/*callback_opaque*/void*, IRBB*);
 
       /* IN: debug: trace vex activity at various points */
       Int     traceflags;
diff --git a/test_main.c b/test_main.c
index ddc0bb1..0ccfec6 100644
--- a/test_main.c
+++ b/test_main.c
@@ -53,7 +53,7 @@
 static IRBB* mc_instrument ( IRBB*, VexGuestLayout*, IRType, IRType );
 #endif
 
-static Bool chase_into_not_ok ( Addr64 dst ) { return False; }
+static Bool chase_into_not_ok ( void* opaque, Addr64 dst ) { return False; }
 
 int main ( int argc, char** argv )
 {
@@ -155,7 +155,7 @@
 #endif
       vta.guest_bytes     = origbuf;
       vta.guest_bytes_addr = (Addr64)orig_addr;
-      vta.guest_bytes_addr_noredir = (Addr64)orig_addr;
+      vta.callback_opaque = NULL;
       vta.chase_into_ok   = chase_into_not_ok;
       vta.guest_extents   = &vge;
       vta.host_bytes      = transbuf;
@@ -174,7 +174,7 @@
       vta.instrument2     = NULL;
 #endif
       vta.do_self_check   = False;
-      vta.do_set_NRADDR   = False;
+      vta.preamble_function = NULL;
       vta.traceflags      = TEST_FLAGS;
 #if 1 /* x86, amd64 hosts */
       vta.dispatch        = (void*)0x12345678;