From: Julian Seward Date: Wed, 27 Oct 2004 23:00:55 +0000 (+0000) Subject: Changes pertaining to supporting instrumentation: X-Git-Tag: svn/VALGRIND_3_0_1^2~895 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=02bdfc7c494d86ce097d1460bb3a08c82ec31db6;p=thirdparty%2Fvalgrind.git Changes pertaining to supporting instrumentation: * 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 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index db5a476fe1..a7476a0291 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -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 diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 9e206935c6..7e370bef2f 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -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 ); } diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 0ee1ceb83b..ab64b8c71f 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -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; diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 12a6fb8a0a..fd00ef9af0 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -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 */ diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index be4436cb27..551950b26a 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -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(); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 162ec50f2a..4a1acdabe4 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -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; diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index 8f60330841..0615ecf66f 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -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]); diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index d36783c382..fb5f3d6386 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -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 */ diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index bc2e880420..8d09ea7fed 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -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 ------------------ */