]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Changes pertaining to supporting instrumentation:
authorJulian Seward <jseward@acm.org>
Wed, 27 Oct 2004 23:00:55 +0000 (23:00 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 27 Oct 2004 23:00:55 +0000 (23:00 +0000)
* Constructors for easier construction thereof, and also of
  argument vectors for both clean and dirty helpers.

* Allow/require instrumenters to supply helper-lookup functions.

* Clarify situation re whether or not dirty helpers get passed
  a pointer to the guest state.

* Sanity check IR after instrumentation.

Myriad other changes to make this all work.

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

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/main/vex_main.c
VEX/pub/libvex.h
VEX/pub/libvex_ir.h

index db5a476fe16997e27d1575a32cb4e0c68ea7bdc5..a7476a029159f616faf2eb055e2da89a5cb15706 100644 (file)
@@ -29,7 +29,7 @@ IRBB* bbToIR_X86Instr ( UChar* x86code,
 /* Used by the back end to look up addresses of helper
    function calls inserted by bbToIR_X86Instr. */
 extern
-Addr64 x86guest_findhelper ( Char* function_name );
+HWord x86guest_findhelper ( Char* function_name );
 
 /* Used by the optimiser to specialise calls to helpers. */
 extern
index 9e206935c64a4635912f02e97393df43c58f7afc..7e370bef2f5d4e349598477c9b9ef80494fb37df 100644 (file)
@@ -24,9 +24,9 @@ static UInt  calculate_FXAM ( UInt tag, ULong dbl );
 static ULong calculate_RCR  ( UInt arg, UInt rot_amt, UInt eflags_in, UInt sz );
 
 /* --- DIRTY HELPERS --- */
-static ULong loadF80le  ( VexGuestX86State*, UInt );
-static void  storeF80le ( VexGuestX86State*, UInt, ULong );
-static void  dirtyhelper_CPUID ( VexGuestX86State* st );
+static ULong loadF80le  ( UInt );
+static void  storeF80le ( UInt, ULong );
+static void  dirtyhelper_CPUID ( VexGuestX86State* );
 
 
 /* This file contains helper functions for x86 guest code.
@@ -35,8 +35,6 @@ static void  dirtyhelper_CPUID ( VexGuestX86State* st );
    this file will be compiled to host machine code, so that
    all makes sense.  
 
-   x86guest_findhelper() is the only exported function. 
-
    Only change the signatures of these helper functions very
    carefully.  If you change the signature here, you'll have to change
    the parameters passed to it in the IR calls constructed by
@@ -598,26 +596,25 @@ static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst )
 }
 
 
-Addr64 x86guest_findhelper ( Char* function_name )
+HWord x86guest_findhelper ( Char* function_name )
 {
    if (vex_streq(function_name, "calculate_condition"))
-      return (Addr64)(Addr32)(& calculate_condition);
+      return (HWord)(& calculate_condition);
    if (vex_streq(function_name, "calculate_eflags_c"))
-      return (Addr64)(Addr32)(& calculate_eflags_c);
+      return (HWord)(& calculate_eflags_c);
    if (vex_streq(function_name, "calculate_eflags_all"))
-      return (Addr64)(Addr32)(& calculate_eflags_all);
+      return (HWord)(& calculate_eflags_all);
    if (vex_streq(function_name, "calculate_FXAM"))
-      return (Addr64)(Addr32)(& calculate_FXAM);
+      return (HWord)(& calculate_FXAM);
    if (vex_streq(function_name, "storeF80le"))
-      return (Addr64)(Addr32)(& storeF80le);
+      return (HWord)(& storeF80le);
    if (vex_streq(function_name, "loadF80le"))
-      return (Addr64)(Addr32)(& loadF80le);
+      return (HWord)(& loadF80le);
    if (vex_streq(function_name, "calculate_RCR"))
-      return (Addr64)(Addr32)(& calculate_RCR);
+      return (HWord)(& calculate_RCR);
    if (vex_streq(function_name, "dirtyhelper_CPUID"))
-      return (Addr64)(Addr32)(& dirtyhelper_CPUID);
-   vex_printf("\nx86 guest: can't find helper: %s\n", function_name);
-   vpanic("x86guest_findhelper");
+      return (HWord)(& dirtyhelper_CPUID);
+   return 0; /* not found */
 }
 
 /* Used by the optimiser to try specialisations.  Returns an
@@ -1194,7 +1191,7 @@ static void convert_f80le_to_f64le ( /*IN*/UChar* f80, /*OUT*/UChar* f64 )
 
 /* CALLED FROM GENERATED CODE */
 /* DIRTY HELPER (reads guest memory) */
-static ULong loadF80le ( VexGuestX86State* st, UInt addrU )
+static ULong loadF80le ( UInt addrU )
 {
    ULong f64;
    convert_f80le_to_f64le ( (UChar*)addrU, (UChar*)&f64 );
@@ -1203,7 +1200,7 @@ static ULong loadF80le ( VexGuestX86State* st, UInt addrU )
 
 /* CALLED FROM GENERATED CODE */
 /* DIRTY HELPER (writes guest memory) */
-static void storeF80le ( VexGuestX86State* st, UInt addrU, ULong f64 )
+static void storeF80le ( UInt addrU, ULong f64 )
 {
    convert_f64le_to_f80le( (UChar*)&f64, (UChar*)addrU );
 }
index 0ee1ceb83b38b1bd5ac30943dda13cfb2c545dd2..ab64b8c71fd93be4b6b491d7942de83f5ae4683a 100644 (file)
@@ -4058,50 +4058,41 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                      ULong loadF80le ( VexGuestX86State*, UInt )
                   addr holds the address.  First, do a dirty call to
                   get hold of the data. */
-               /* give details of args, and where to call */
-               IRDirty* d;
-               DIP("fldt %s", dis_buf);
-               d          = emptyIRDirty();
-               d->name    = "loadF80le";
-               d->args    = LibVEX_Alloc(2 * sizeof(IRTemp));
-               d->args[0] = mkexpr(addr);
-               d->args[1] = NULL;
-               d->tmp     = newTemp(Ity_I64);
+               IRTemp   val  = newTemp(Ity_I64);
+               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
+
+               IRDirty* d = unsafeIRDirty_1_N ( val, "loadF80le", args );
                /* declare that we're reading memory */
                d->mFx   = Ifx_Read;
                d->mAddr = mkexpr(addr);
                d->mSize = 10;
-               /* declare that we don't mess with guest state */
-               d->nFxState = 0;
-               /* execute the dirty call, dumping the result in d->tmp. */
+
+               /* execute the dirty call, dumping the result in val. */
                stmt( IRStmt_Dirty(d) );
                fp_push();
-               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(d->tmp)));
+               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
+
+               DIP("fldt %s", dis_buf);
                break;
             }
 
             case 7: { /* FSTP extended-real */
                /* Uses dirty helper: void storeF80le ( UInt, ULong ) */
-               IRDirty* d;
-               DIP("fldt %s", dis_buf);
-               d          = emptyIRDirty();
-               d->name    = "storeF80le";
-               /* takes 2 args */
-               d->args = LibVEX_Alloc(3 * sizeof(IRTemp));
-               d->args[0] = mkexpr(addr);
-               d->args[1] = unop(Iop_ReinterpF64asI64, get_ST(0));
-               d->args[2] = NULL;
-               /* returns nothing */
-               d->tmp = INVALID_IRTEMP;
+               IRExpr** args 
+                  = mkIRExprVec_2( mkexpr(addr), 
+                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
+
+               IRDirty* d = unsafeIRDirty_0_N ( "storeF80le", args );
                /* declare we're writing memory */
                d->mFx   = Ifx_Write;
                d->mAddr = mkexpr(addr);
                d->mSize = 10;
-               /* declare that we don't mess with guest state */
-               d->nFxState = 0;
+
                /* execute the dirty call. */
                stmt( IRStmt_Dirty(d) );
                fp_pop();
+
+               DIP("fstpt %s", dis_buf);
                break;
             }
 
@@ -8985,18 +8976,10 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
                void dirtyhelper_CPUID ( VexGuestX86State* )
             declared to mod eax, wr ebx, ecx, edx
          */
-         /* give details of args, and where to call */
-         IRDirty* d;
-         d          = emptyIRDirty();
-         d->name    = "dirtyhelper_CPUID";
-         d->args    = LibVEX_Alloc(1 * sizeof(IRTemp));
-         d->args[0] = NULL;
-         d->tmp     = INVALID_IRTEMP;
-         /* declare that we're not accessing memory */
-         d->mFx   = Ifx_None;
-         d->mAddr = NULL;
-         d->mSize = 0;
+         IRExpr** args = mkIRExprVec_0();
+         IRDirty* d    = unsafeIRDirty_0_N ( "dirtyhelper_CPUID", args );
          /* declare guest state effects */
+         d->needsBBP = True;
          d->nFxState = 4;
          d->fxState[0].fx     = Ifx_Modify;
          d->fxState[0].offset = OFFB_EAX;
index 12a6fb8a0a8e39b00fc5241a6c9d5b50951a0730..fd00ef9af041557332801c941b48ab5f34fa91dc 100644 (file)
@@ -477,7 +477,8 @@ extern Int          emit_X86Instr        ( UChar* buf, Int nbuf, X86Instr* );
 extern X86Instr*    genSpill_X86         ( HReg rreg, Int offset );
 extern X86Instr*    genReload_X86        ( HReg rreg, Int offset );
 extern void         getAllocableRegs_X86 ( Int*, HReg** );
-extern HInstrArray* iselBB_X86           ( IRBB*, Addr64(*)(Char*) );
+extern HInstrArray* iselBB_X86           ( IRBB*, HWord(*)(Char*), 
+                                                  HWord(*)(Char*) );
 
 #endif /* ndef __LIBVEX_X86H_DEFS_H */
 
index be4436cb27977a0eb5119309fe1ec141f380e76f..551950b26a38fe05ecca88c2f5ac64998d3318c8 100644 (file)
@@ -143,7 +143,11 @@ static IRExpr* bind ( Int binder )
 
 /* This carries around:
 
-   - A function for looking up the address of helper functions.
+   - A function for looking up the address of vex front-end supplied
+     helper functions.
+
+   - A function for looking up the address of tool-supplied helper
+     functions.
 
    - A mapping from IRTemp to IRType, giving the type of any IRTemp we
      might encounter.  This is computed before insn selection starts,
@@ -169,7 +173,8 @@ static IRExpr* bind ( Int binder )
 
 typedef
    struct {
-      Addr64       (*find_helper)(Char*);
+      HWord        (*find_helper_vex)(Char*);
+      HWord        (*find_helper_tool)(Char*);
 
       IRTypeEnv*   type_env;
 
@@ -295,24 +300,48 @@ static Int pushArg ( ISelEnv* env, IRExpr* arg )
    vpanic("pushArg(x86): can't handle arg of this type");
 }
 
+
+/* Find the address of a helper function, first by consulting vex's
+   own front end, and if that doesn't work, by consulting the
+   tool-supplied lookup function. */
+
+static
+HWord findHelper ( ISelEnv* env, Char* name )
+{
+   HWord helper;
+
+   /* Since the host -- for which we are generating code, and on which
+      the helpers are compiled -- is a 32-bit machine (x86) -- HWord
+      must be a 32-bit type. */
+   vassert(sizeof(HWord) == 4);
+
+   /* First see if vex's own front end has a binding for this fn. */
+   helper = env->find_helper_vex(name);
+
+   /* No?  Try the tool-supplied function. */
+   if (helper == 0 && env->find_helper_tool)
+      helper = env->find_helper_tool(name);
+
+   if (helper != 0)
+      return helper;
+
+   vex_printf("\nvex x86 back end: can't find helper: %s\n", name);
+   vpanic("findHelper(x86,host)");
+}
+
+
 /* Complete the call to a helper function, by calling the 
    helper and clearing the args off the stack. */
 
 static 
 void callHelperAndClearArgs ( ISelEnv* env, Char* name, Int n_arg_ws )
 {
-   Addr64 helper;
-   UInt   target;
-
-   /* Find the function to call.  Since the host -- for which we are
-      generating code -- is a 32-bit machine (x86) -- the upper 32
-      bits of the helper address should be zero. */
-   helper = env->find_helper(name);
-   vassert((helper & 0xFFFFFFFF00000000LL) == 0);
-   target = helper & 0xFFFFFFFF;
+   HWord helper = findHelper( env, name );
+   vassert(sizeof(HWord) == 4);
+
    addInstr(env, X86Instr_Alu32R(
                     Xalu_MOV,
-                    X86RMI_Imm(target),
+                    X86RMI_Imm(helper),
                     hregX86_EAX()));
    addInstr(env, X86Instr_Call(hregX86_EAX()));
    if (n_arg_ws > 0)
@@ -2134,10 +2163,14 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       for (i = n_args-1; i >= 0; i--)
          n_arg_ws += pushArg(env, d->args[i]);
 
-      /* and finally the leftmost argument, the guest state pointer,
-         which is in %ebp. */
-      addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
-      n_arg_ws++;
+      if (d->nFxState == 0)
+         vassert(!d->needsBBP);
+      if (d->nFxState > 0 && d->needsBBP) {
+         /* If the helper claims it accesses guest state, give it a
+            first argument which is the guest state pointer (%ebp). */
+         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
+         n_arg_ws++;
+      }
 
       /* call the helper, and get the args off the stack afterwards. */
       callHelperAndClearArgs( env, d->name, n_arg_ws );
@@ -2204,7 +2237,9 @@ static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
 
 /* Translate an entire BB to x86 code. */
 
-HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) )
+HInstrArray* iselBB_X86 ( IRBB* bb, 
+                          HWord(*find_helper_vex)(Char*),
+                          HWord(*find_helper_tool)(Char*) )
 {
    Int     i, j;
    HReg    hreg, hregHI;
@@ -2213,8 +2248,9 @@ HInstrArray* iselBB_X86 ( IRBB* bb, Addr64(*find_helper)(Char*) )
    ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
    env->vreg_ctr = 0;
 
-   /* Register helper-function-finder. */
-   env->find_helper = find_helper;
+   /* Register helper-function-finders. */
+   env->find_helper_vex  = find_helper_vex;
+   env->find_helper_tool = find_helper_tool;
 
    /* Set up output code array. */
    env->code = newHInstrArray();
index 162ec50f2a11cc51be97e8123a35956b492e5028..4a1acdabe4399ac65450b30be6be4dde9d1bfb47 100644 (file)
@@ -274,7 +274,9 @@ void ppIREffect ( IREffect fx )
 void ppIRDirty ( IRDirty* d )
 {
    Int i;
-   vex_printf("DIRTY ");
+   vex_printf("DIRTY");
+   if (d->needsBBP)
+      vex_printf(" NeedsBBP");
    if (d->mFx != Ifx_None) {
       ppIREffect(d->mFx);
       vex_printf("-mem(");
@@ -285,7 +287,7 @@ void ppIRDirty ( IRDirty* d )
       ppIREffect(d->fxState[i].fx);
       vex_printf("-gst(%d,%d) ", d->fxState[i].offset, d->fxState[i].size);
    }
-   vex_printf("::: ");
+   vex_printf(" ::: ");
    if (d->tmp != INVALID_IRTEMP) {
       ppIRTemp(d->tmp);
       vex_printf(" = ");
@@ -539,10 +541,32 @@ IRExpr* IRExpr_Mux0X ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX ) {
 }
 
 
+/* Constructors for NULL-terminated IRExpr expression vectors,
+   suitable for use as arg lists in clean/dirty helper calls. */
+
+IRExpr** mkIRExprVec_0 ( void ) {
+   IRExpr** vec = LibVEX_Alloc(1 * sizeof(IRExpr*));
+   vec[0] = NULL;
+   return vec;
+}
+IRExpr** mkIRExprVec_1 ( IRExpr* arg1 ) {
+   IRExpr** vec = LibVEX_Alloc(2 * sizeof(IRExpr*));
+   vec[0] = arg1;
+   vec[1] = NULL;
+   return vec;
+}
+IRExpr** mkIRExprVec_2 ( IRExpr* arg1, IRExpr* arg2 ) {
+   IRExpr** vec = LibVEX_Alloc(3 * sizeof(IRExpr*));
+   vec[0] = arg1;
+   vec[1] = arg2;
+   vec[2] = NULL;
+   return vec;
+}
+
+
 /* Constructors -- IRDirty */
 
-IRDirty* emptyIRDirty ( void )
-{
+IRDirty* emptyIRDirty ( void ) {
    IRDirty* d = LibVEX_Alloc(sizeof(IRDirty));
    d->name     = NULL;
    d->args     = NULL;
@@ -550,10 +574,25 @@ IRDirty* emptyIRDirty ( void )
    d->mFx      = Ifx_None;
    d->mAddr    = NULL;
    d->mSize    = 0;
+   d->needsBBP = False;
    d->nFxState = 0;
    return d;
 }
 
+IRDirty* unsafeIRDirty_0_N ( Char* name, IRExpr** args ) {
+   IRDirty* d = emptyIRDirty();
+   d->name = name;
+   d->args = args;
+   return d;
+}
+IRDirty* unsafeIRDirty_1_N ( IRTemp dst, Char* name, IRExpr** args ) {
+   IRDirty* d = emptyIRDirty();
+   d->name = name;
+   d->args = args;
+   d->tmp  = dst;
+   return d;
+}
+
 
 /* Constructors -- IRStmt */
 
@@ -733,6 +772,7 @@ IRDirty* dopyIRDirty ( IRDirty* d )
    d2->mFx   = d->mFx;
    d2->mAddr = d->mAddr==NULL ? NULL : dopyIRExpr(d->mAddr);
    d2->mSize = d->mSize;
+   d2->needsBBP = d->needsBBP;
    d2->nFxState = d->nFxState;
    for (i = 0; i < d2->nFxState; i++)
       d2->fxState[i] = d->fxState[i];
@@ -1335,6 +1375,8 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy )
          }
          if (d->nFxState < 0 || d->nFxState > VEX_N_FXSTATE)
             goto bad_dirty;
+         if (d->nFxState == 0 && d->needsBBP)
+            goto bad_dirty;
          for (i = 0; i < d->nFxState; i++) {
             if (d->fxState[i].fx == Ifx_None) goto bad_dirty;
             if (d->fxState[i].size <= 0) goto bad_dirty;
index 8f60330841fbb5552040df21e2075f62a8528629..0615ecf66f29ed3465bdc98076f790c128b13ec7 100644 (file)
@@ -131,6 +131,7 @@ TranslateResult LibVEX_Translate (
    Int* host_bytes_used,
    /* IN: optionally, an instrumentation function. */
    IRBB* (*instrument) ( IRBB* ),
+   HWord (*tool_findhelper) ( Char* ),
    /* IN: optionally, an access check function for guest code. */
    Bool (*byte_accessible) ( Addr64 ),
    /* IN: if > 0, use this verbosity for this bb */
@@ -149,11 +150,11 @@ TranslateResult LibVEX_Translate (
    HInstr*      (*genReload)   ( HReg, Int );
    void         (*ppInstr)     ( HInstr* );
    void         (*ppReg)       ( HReg );
-   HInstrArray* (*iselBB)      ( IRBB*, Addr64(*)(Char*) );
+   HInstrArray* (*iselBB)      ( IRBB*, HWord(*)(Char*), HWord(*)(Char*) );
    IRBB*        (*bbToIR)      ( UChar*, Addr64, Int*, 
                                          Bool(*)(Addr64), Bool );
    Int          (*emit)        ( UChar*, Int, HInstr* );
-   Addr64       (*findHelper)  ( Char* );
+   HWord        (*findHelper)  ( Char* );
    IRExpr*      (*specHelper)  ( Char*, IRExpr** );
    Bool         (*preciseMemExnsFn) ( Int, Int );
 
@@ -163,6 +164,7 @@ TranslateResult LibVEX_Translate (
    HInstrArray* rcode;
    Int          i, j, k, out_used, saved_verbosity, guest_sizeB;
    UChar        insn_bytes[32];
+   IRType       guest_word_size;
 
    available_real_regs    = NULL;
    n_available_real_regs  = 0;
@@ -179,6 +181,7 @@ TranslateResult LibVEX_Translate (
    findHelper             = NULL;
    specHelper             = NULL;
    preciseMemExnsFn       = NULL;
+   guest_word_size        = Ity_INVALID;
 
    saved_verbosity = vex_verbosity;
    if (bb_verbosity > 0)
@@ -215,6 +218,7 @@ TranslateResult LibVEX_Translate (
          findHelper       = x86guest_findhelper;
          specHelper       = x86guest_spechelper;
          guest_sizeB      = sizeof(VexGuestX86State);
+        guest_word_size  = Ity_I32;
          break;
       default:
          vpanic("LibVEX_Translate: unsupported guest insn set");
@@ -244,12 +248,12 @@ TranslateResult LibVEX_Translate (
    }
 
    /* Sanity check the initial IR. */
-   sanityCheckIRBB(irbb, Ity_I32);
+   sanityCheckIRBB(irbb, guest_word_size);
 
    /* Clean it up, hopefully a lot. */
    irbb = do_iropt_BB ( irbb, specHelper, preciseMemExnsFn, 
                               guest_bytes_addr );
-   sanityCheckIRBB(irbb, Ity_I32);
+   sanityCheckIRBB(irbb, guest_word_size);
 
    if (vex_verbosity > 0) {
       vex_printf("\n-------- After IR optimisation --------\n");
@@ -258,11 +262,13 @@ TranslateResult LibVEX_Translate (
    }
 
    /* Get the thing instrumented. */
-   if (instrument)
+   if (instrument) {
       irbb = (*instrument)(irbb);
+      sanityCheckIRBB(irbb, guest_word_size);
+   }
 
    /* Turn it into virtual-registerised code. */
-   vcode = iselBB ( irbb, findHelper );
+   vcode = iselBB ( irbb, findHelper, tool_findhelper );
 
    if (vex_verbosity > 0) {
       vex_printf("\n-------- Virtual registerised code --------\n");
@@ -294,12 +300,12 @@ TranslateResult LibVEX_Translate (
    /* Assemble */
    out_used = 0; /* tracks along the host_bytes array */
    for (i = 0; i < rcode->arr_used; i++) {
-      if (vex_verbosity > 1) {
+      if (vex_verbosity > 2) {
          ppInstr(rcode->arr[i]);
          vex_printf("\n");
       }
       j = (*emit)( insn_bytes, 32, rcode->arr[i] );
-      if (vex_verbosity > 1) {
+      if (vex_verbosity > 2) {
          for (k = 0; k < j; k++)
            if (insn_bytes[k] < 16)
                vex_printf("0%x ",  (UInt)insn_bytes[k]);
index d36783c38242b5332896c5245896df02a5d5d1b8..fb5f3d6386fccf28cd19347663aa4ecc2afdd5d4 100644 (file)
@@ -118,6 +118,7 @@ TranslateResult LibVEX_Translate (
    Int* host_bytes_used,
    /* IN: optionally, an instrumentation function. */
    IRBB* (*instrument) ( IRBB* ),
+   HWord (*tool_findhelper) ( Char* ),
    /* IN: optionally, an access check function for guest code. */
    Bool (*byte_accessible) ( Addr64 ),
    /* IN: if > 0, use this verbosity for this bb */
index bc2e8804200ef8d8f4772353af7aa0fcce90585b..8d09ea7feddeb9c3c503263c0479118fbff6c961 100644 (file)
@@ -322,8 +322,7 @@ typedef
    details about what the helper does (and you better be telling the
    truth, otherwise any derived instrumentation will be wrong).  Also
    IRStmt_Dirty inhibits various IR optimisations and so can cause
-   quite poor code to be generated.  Use it as little as possible, and
-   in non-performance-critical situations only.
+   quite poor code to be generated.  Try to avoid it.  
 */
 
 /* The possible kinds of expressions are as follows: */
@@ -404,12 +403,19 @@ extern IRExpr* IRExpr_CCall  ( Char* name, IRType retty, IRExpr** args );
 extern IRExpr* IRExpr_Mux0X  ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX );
 
 extern IRExpr*  dopyIRExpr ( IRExpr* );
-extern IRExpr** sopyIRExprVec ( IRExpr** );
-extern IRExpr** dopyIRExprVec ( IRExpr** );
-
 
 extern void ppIRExpr ( IRExpr* );
 
+/* NULL-terminated IRExpr expression vectors, suitable for use as arg
+   lists in clean/dirty helper calls. */
+
+extern IRExpr** mkIRExprVec_0 ( void );
+extern IRExpr** mkIRExprVec_1 ( IRExpr* arg1 );
+extern IRExpr** mkIRExprVec_2 ( IRExpr* arg1, IRExpr* arg2 );
+
+extern IRExpr** sopyIRExprVec ( IRExpr** );
+extern IRExpr** dopyIRExprVec ( IRExpr** );
+
 
 /* ------------------ Dirty helper calls ------------------ */
 
@@ -420,30 +426,14 @@ extern void ppIRExpr ( IRExpr* );
    results and/or do different things when called repeated with the
    same arguments, by means of storing private state.
 
-   The supplied arguments are all IRTemps, to attempt to sidestep any
-   semantic difficulties created by allowing them to be arbitrary
-   expressions (although I can't think of any such).  If a value is
-   returned, it is assigned to the nominated return temporary.
+   If a value is returned, it is assigned to the nominated return
+   temporary.
 
    Dirty calls are statements rather than expressions for obvious
-   reasons.  IRTemps may or may not stay alive across them.  A precise
-   statement is: any IRTemp which depends, directly or indirectly, on
-   any memory or guest state segments which the call claims to write
-   or modify, must be regarded as invalid after the call and therefore
-   may not be used after it.
-
-   It would be nice to automatically check this in the sanity checker,
-   but doing so exactly is difficult (although probably possible).
-   Some approximation scheme will be needed.  This would rule out some
-   constructions which are actually valid, but not interesting, whilst
-   still catching all invalid constructions.
-
-   One obvious if pessimistic approximation is to say that *all*
-   IRTemps are killed across a Dirty call.  That's easy to
-   mechanically check, but it's not going to work with
-   instrumentation, as doing the shadow state updates after the call
-   will surely require reading temps defined before the call.  Needs
-   further consideration.
+   reasons.  If a dirty call is stated as writing guest state, any
+   values derived from the written parts of the guest state are
+   invalid.  Similarly, if the dirty call is stated as writing
+   memory, any loaded values are invalidated by it.
 
    In order that instrumentation is possible, the call must state, and
    state correctly
@@ -454,6 +444,13 @@ extern void ppIRExpr ( IRExpr* );
    * whether it reads, writes or modifies guest state, and if so which
      pieces (several pieces may be stated, and currently their extents
      must be known at translation-time).
+
+   Normally, code is generated to pass just the args to the helper.
+   However, if .needsBBP is set, then an extra first argument is
+   passed, which is the baseblock pointer, so that the callee can
+   access the guest state.  It is invalid for .nFxState to be zero
+   but .needsBBP to be True, since .nFxState==0 is a claim that the
+   call does not access guest state.
 */
 
 #define VEX_N_FXSTATE  4   /* enough for CPUID on x86 */
@@ -483,7 +480,8 @@ typedef
       Int      mSize;  /* of access, or zero if mFx==Ifx_None */
 
       /* Guest state effects; up to N allowed */
-      Int nFxState; /* must be 0 .. VEX_N_FXSTATE */
+      Bool needsBBP; /* True => also pass guest state ptr to callee */
+      Int  nFxState; /* must be 0 .. VEX_N_FXSTATE */
       struct {
          IREffect fx;   /* read, write or modify? */
          Int      offset;
@@ -497,6 +495,17 @@ extern IRDirty* emptyIRDirty ( void );
 
 extern IRDirty* dopyIRDirty ( IRDirty* );
 
+/* A handy function which takes some of the tedium out of constructing
+   dirty helper calls.  The called function impliedly does not return
+   any value.  The call is marked as accessing neither guest state nor
+   memory (hence the "unsafe" designation) -- you can mess with this
+   later if need be.*/
+extern IRDirty* unsafeIRDirty_0_N ( Char* name, IRExpr** args );
+
+/* Similarly, make a zero-annotation dirty call which returns a value,
+   and assign that to the given temp. */
+extern IRDirty* unsafeIRDirty_1_N ( IRTemp dst, Char* name, IRExpr** args );
+
 
 /* ------------------ Statements ------------------ */