/* Converts an IRExpr into 1 or 2 "flat" expressions of type Int */ static void packToI32 ( IRSB* sb, IRExpr* e, IRExpr* res[2]) { //IRType eType = Ity_I32; IRTemp tmp64; res[1]=NULL; switch (typeOfIRExpr(sb->tyenv,e)) { case Ity_I1: res[0]= IRExpr_Unop(Iop_1Uto32,e); break; case Ity_I8: res[0]= IRExpr_Unop(Iop_8Uto32,e); break; case Ity_I16: res[0]= IRExpr_Unop(Iop_16Uto32,e); break; case Ity_I32: res[0]= e; return; case Ity_F32: res[0]= IRExpr_Unop(Iop_ReinterpF32asI32,e); break; case Ity_I64: res[0]= IRExpr_Unop(Iop_64to32, e); res[1]= IRExpr_Unop(Iop_64HIto32, e); break; case Ity_F64: tmp64 = newIRTemp(sb->tyenv, Ity_I64); addStmtToIRSB(sb, IRStmt_WrTmp(tmp64, IRExpr_Unop(Iop_ReinterpF64asI64,e))); res[0]= IRExpr_Unop(Iop_64to32, IRExpr_RdTmp(tmp64) ); res[1]= IRExpr_Unop(Iop_64HIto32, IRExpr_RdTmp(tmp64) ); break; case Ity_V128: /* 128-bit SIMD */ case Ity_I128: /* 128-bit scalar */ case Ity_INVALID: default: VG_(tool_panic)("COJAC cannot packToI32..."); break; } IRTemp myArg = newIRTemp(sb->tyenv, Ity_I32); addStmtToIRSB(sb, IRStmt_WrTmp(myArg, res[0])); res[0]=IRExpr_RdTmp(myArg); // now that's a "flat" expression if (res[1]==NULL) return; IRTemp myArg2 = newIRTemp(sb->tyenv, Ity_I32); addStmtToIRSB(sb, IRStmt_WrTmp(myArg2, res[1])); res[1]=IRExpr_RdTmp(myArg2); // now that's a "flat" expression }
/* Converts an IRExpr into 1 or 2 "flat" expressions of type Long */ static void packToI64 ( IRSB* sb, IRExpr* e, IRExpr* res[2], IROp irop) { res[1]=NULL; // won't be used at all IRTemp tmp64; switch (typeOfIRExpr(sb->tyenv,e)) { case Ity_I1: res[0]= IRExpr_Unop(Iop_1Uto64,e); break; case Ity_I8: res[0]= IRExpr_Unop(Iop_8Uto64,e); break; case Ity_I16: res[0]= IRExpr_Unop(Iop_16Uto64,e); break; case Ity_I32: res[0]= IRExpr_Unop(Iop_32Uto64,e); break; case Ity_F32: e = IRExpr_Unop(Iop_ReinterpF32asI32,e); res[0]= IRExpr_Unop(Iop_32Uto64,e); break; case Ity_I64: res[0]= e; return; case Ity_F64: res[0]= IRExpr_Unop(Iop_ReinterpF64asI64,e); break; case Ity_V128: /* 128-bit SIMD */ //tmp64 = newIRTemp(sb->tyenv, Ity_I64); //addStmtToIRSB(sb, IRStmt_WrTmp(tmp64, IRExpr_Unop(Iop_V128to64,e))); //res[0]= IRExpr_Unop(Iop_64to32, IRExpr_RdTmp(tmp64) ); //res[1]= IRExpr_Unop(Iop_64HIto32, IRExpr_RdTmp(tmp64) ); res[0]= IRExpr_Unop(Iop_V128to64, e ); if (dropV128HiPart(irop)) break; res[1]= IRExpr_Unop(Iop_V128HIto64, e ); break; case Ity_I128: /* 128-bit scalar */ case Ity_INVALID: default: VG_(tool_panic)("COJAC cannot packToI64..."); break; } IRTemp myArg = newIRTemp(sb->tyenv, Ity_I64); addStmtToIRSB(sb, IRStmt_WrTmp(myArg, res[0])); res[0]=IRExpr_RdTmp(myArg); // now that's a "flat" expression if (res[1]==NULL) return; // ... else it was 128-bit SIMD IRTemp myArg2 = newIRTemp(sb->tyenv, Ity_I64); addStmtToIRSB(sb, IRStmt_WrTmp(myArg2, res[1])); res[1]=IRExpr_RdTmp(myArg2); // now that's a "flat" expression }
static IRExpr* assignNew_HWord(IRSB* sb_out, IRExpr* expr) { IRTemp tmp = newIRTemp(sb_out->tyenv, Ity_I32); switch (typeOfIRExpr(sb_out->tyenv, expr)) { case Ity_I1: addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_1Uto32, expr))); break; case Ity_I8: addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_8Uto32, expr))); break; case Ity_I16: addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_16Uto32, expr))); break; case Ity_I32: addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, expr)); break; case Ity_I64: addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, IRExpr_Unop(Iop_64to32, expr))); break; default: VG_(tool_panic)("assignNew_HWord"); } return IRExpr_RdTmp(tmp); }
/* Bind the given expression to a new temporary, and return the temporary. This effectively converts an arbitrary expression into an IRAtom. */ static IRExpr* assignNew(IRSB* sb_out, IRExpr* expr) { IRTemp tmp = newIRTemp(sb_out->tyenv, typeOfIRExpr(sb_out->tyenv, expr)); addStmtToIRSB(sb_out, IRStmt_WrTmp(tmp, expr)); return IRExpr_RdTmp(tmp); }
static IRAtom* assignNew ( IRSB* sb, IRExpr* e ) { IRTemp t; IRType ty = typeOfIRExpr(sb->tyenv, e); t = newIRTemp(sb->tyenv, ty); assign(sb, t, e); return mkexpr(t); }
PyObject *pyIRTypeEnv_newTemp(pyIRTypeEnv *self, PyObject *type) { IRType t; const char *t_str = PyString_AsString(type); if (!t_str) { PyErr_SetString(VexException, "Unrecognized type argument to IRTypeEnv.newTemp"); return NULL; } PYVEX_ENUM_FROMSTR(IRType, t, t_str, return NULL); return PyInt_FromLong(newIRTemp(self->wrapped, t)); }
/* Create a new IRTemp of type 'ty' and kind 'kind', and add it to both the table in pce->sb and to our auxiliary mapping. Note that newTemp may cause pce->tmpMap to resize, hence previous results from VG_(indexXA)(pce->tmpMap) are invalidated. */ static IRTemp newTemp ( PCEnv* pce, IRType ty, TempKind kind ) { Word newIx; TempMapEnt ent; IRTemp tmp = newIRTemp(pce->sb->tyenv, ty); ent.kind = kind; ent.shadow = IRTemp_INVALID; newIx = VG_(addToXA)( pce->qmpMap, &ent ); tl_assert(newIx == (Word)tmp); return tmp; }
static IRSB * bcg_instrument(VgCallbackClosure* closure, IRSB* bb, VexGuestLayout* layout, VexGuestExtents* vge, IRType gWordTy, IRType hWordTy) { unsigned long rip = 0; int i; if (bb->jumpkind != Ijk_Ret && bb->next->tag != Iex_Const) { IRTemp tmp; for (i = bb->stmts_used - 1; i >= 0; i--) { if (bb->stmts[i]->tag == Ist_IMark) { rip = bb->stmts[i]->Ist.IMark.addr; break; } } tl_assert(i >= 0); if (bb->next->tag == Iex_RdTmp) { tmp = bb->next->Iex.RdTmp.tmp; } else { tmp = newIRTemp(bb->tyenv, Ity_I64); addStmtToIRSB(bb, IRStmt_WrTmp(tmp, bb->next)); bb->next = IRExpr_RdTmp(tmp); } addStmtToIRSB(bb, IRStmt_Dirty( unsafeIRDirty_0_N( 0, "log_call", log_call, mkIRExprVec_3( IRExpr_Const(IRConst_U64(rip)), IRExpr_Const(IRConst_U64(bb->jumpkind == Ijk_Call)), bb->next)))); } return bb; }
static IRExpr * log_reads_expr(unsigned tid, IRSB *sb, IRExpr *exp) { if (!exp) return NULL; switch (exp->tag) { case Iex_Get: case Iex_FreeVariable: case Iex_EntryPoint: case Iex_ControlFlow: return exp; case Iex_GetI: { IRExprGetI *e = (IRExprGetI *)exp; return IRExpr_GetI(e->descr, log_reads_expr(tid, sb, e->ix), e->bias, e->tid); } case Iex_Qop: { IRExprQop *e = (IRExprQop *)exp; return IRExpr_Qop(e->op, log_reads_expr(tid, sb, e->arg1), log_reads_expr(tid, sb, e->arg2), log_reads_expr(tid, sb, e->arg3), log_reads_expr(tid, sb, e->arg4)); } case Iex_Triop: { IRExprTriop *e = (IRExprTriop *)exp; return IRExpr_Triop(e->op, log_reads_expr(tid, sb, e->arg1), log_reads_expr(tid, sb, e->arg2), log_reads_expr(tid, sb, e->arg3)); } case Iex_Binop: { IRExprBinop *e = (IRExprBinop *)exp; return IRExpr_Binop(e->op, log_reads_expr(tid, sb, e->arg1), log_reads_expr(tid, sb, e->arg2)); } case Iex_Associative: { IRExprAssociative *e = (IRExprAssociative *)exp; IRExpr **newArgs = alloc_irexpr_array(e->nr_arguments); for (int x = 0; x < e->nr_arguments; x++) newArgs[x] = log_reads_expr(tid, sb, e->contents[x]); return IRExpr_Associative_Claim(e->op, e->nr_arguments, newArgs); } case Iex_Unop: { IRExprUnop *e = (IRExprUnop *)exp; return IRExpr_Unop(e->op, log_reads_expr(tid, sb, e->arg)); } case Iex_Load: { IRExprLoad *e = (IRExprLoad *)exp; IRExpr **args; void *helper; const char *helper_name; IRTemp dest; IRDirty *f; assert(e->addr->type() == Ity_I64); /* Shut compiler up */ helper = (void *)0xf001; helper_name = (const char *)0xdead; #define HLP(x) helper_name = "helper_load_" #x ; helper = (void *)helper_load_ ## x ; switch (e->ty) { case Ity_INVALID: abort(); case Ity_I1: abort(); case Ity_I8: HLP(8); break; case Ity_I16: HLP(16); break; case Ity_I32: HLP(32); break; case Ity_I64: HLP(64); break; case Ity_I128: HLP(128); break; } #undef HLP args = mkIRExprVec_3(log_reads_expr(tid, sb, e->addr), IRExpr_Get(OFFSET_amd64_RSP, Ity_I64, tid, 0), IRExpr_Get(OFFSET_amd64_RIP, Ity_I64, tid, 0)); dest = newIRTemp(sb->tyenv); f = unsafeIRDirty_1_N(threadAndRegister::temp(tid, dest, 0), 0, helper_name, helper, args); addStmtToIRSB(sb, IRStmt_Dirty(f)); return IRExpr_RdTmp(dest, e->ty, tid, 0); } case Iex_Const: return exp; case Iex_CCall: { IRExprCCall *e = (IRExprCCall *)exp; IRExpr **args; int x; int nr_args; for (nr_args = 0; e->args[nr_args]; nr_args++) ; args = alloc_irexpr_array(nr_args + 1); args[nr_args] = NULL; for (x = 0; x < nr_args; x++) args[x] = log_reads_expr(tid, sb, e->args[x]); return IRExpr_CCall(e->cee, e->retty, args); } case Iex_Mux0X: { IRExprMux0X *e = (IRExprMux0X *)exp; return IRExpr_Mux0X(log_reads_expr(tid, sb, e->cond), log_reads_expr(tid, sb, e->expr0), log_reads_expr(tid, sb, e->exprX)); } case Iex_HappensBefore: abort(); } abort(); }
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*/ Bool (*chase_into_ok)(void*,Addr64), /*IN*/ Bool host_bigendian, /*IN*/ VexArch arch_guest, /*IN*/ VexArchInfo* archinfo_guest, /*IN*/ IRType guest_word_type, /*IN*/ Bool do_self_check, /*IN*/ Bool (*preamble_function)(void*,IRBB*), /*IN*/ Int offB_TISTART, /*IN*/ Int offB_TILEN ) { Long delta; Int i, n_instrs, first_stmt_idx; Bool resteerOK, need_to_put_IP, debug_print; DisResult dres; IRStmt* imark; static Int n_resteers = 0; Int d_resteers = 0; Int selfcheck_idx = 0; IRBB* irbb; Addr64 guest_IP_curr_instr; IRConst* guest_IP_bbstart_IRConst = NULL; Bool (*resteerOKfn)(void*,Addr64) = NULL; debug_print = toBool(vex_traceflags & VEX_TRACE_FE); /* Note: for adler32 to work without % operation for the self check, need to limit length of stuff it scans to 5552 bytes. Therefore limiting the max bb len to 100 insns seems generously conservative. */ /* check sanity .. */ vassert(sizeof(HWord) == sizeof(void*)); vassert(vex_control.guest_max_insns >= 1); vassert(vex_control.guest_max_insns < 100); vassert(vex_control.guest_chase_thresh >= 0); vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns); vassert(guest_word_type == Ity_I32 || guest_word_type == Ity_I64); /* Start a new, empty extent. */ vge->n_used = 1; vge->base[0] = guest_IP_bbstart; vge->len[0] = 0; /* And a new IR BB to dump the result into. */ irbb = emptyIRBB(); /* Delta keeps track of how far along the guest_code array we have so far gone. */ delta = 0; n_instrs = 0; /* 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 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) { selfcheck_idx = irbb->stmts_used; addStmtToIRBB( irbb, IRStmt_NoOp() ); addStmtToIRBB( irbb, IRStmt_NoOp() ); addStmtToIRBB( irbb, IRStmt_NoOp() ); addStmtToIRBB( irbb, IRStmt_NoOp() ); addStmtToIRBB( irbb, IRStmt_NoOp() ); } /* 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. */ while (True) { vassert(n_instrs < vex_control.guest_max_insns); /* Regardless of what chase_into_ok says, is chasing permissible at all right now? Set resteerOKfn accordingly. */ resteerOK = toBool( n_instrs < vex_control.guest_chase_thresh /* If making self-checking translations, don't chase .. it makes the checks too complicated. We only want to scan just one sequence of bytes in the check, not a whole bunch. */ && !do_self_check /* we can't afford to have a resteer once we're on the last extent slot. */ && vge->n_used < 3 ); resteerOKfn = resteerOK ? chase_into_ok : const_False; /* This is the IP of the instruction we're just about to deal with. */ guest_IP_curr_instr = guest_IP_bbstart + delta; /* This is the irbb statement array index of the first stmt in this insn. That will always be the instruction-mark descriptor. */ first_stmt_idx = irbb->stmts_used; /* Add an instruction-mark statement. We won't know until after disassembling the instruction how long it instruction is, so just put in a zero length and we'll fix it up later. */ addStmtToIRBB( irbb, IRStmt_IMark( guest_IP_curr_instr, 0 )); /* for the first insn, the dispatch loop will have set %IP, but for all the others we have to do it ourselves. */ need_to_put_IP = toBool(n_instrs > 0); /* Finally, actually disassemble an instruction. */ dres = dis_instr_fn ( irbb, need_to_put_IP, resteerOKfn, callback_opaque, guest_code, delta, guest_IP_curr_instr, arch_guest, archinfo_guest, host_bigendian ); /* stay sane ... */ vassert(dres.whatNext == Dis_StopHere || dres.whatNext == Dis_Continue || dres.whatNext == Dis_Resteer); vassert(dres.len >= 0 && dres.len <= 20); if (dres.whatNext != Dis_Resteer) vassert(dres.continueAt == 0); /* Fill in the insn-mark length field. */ vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used); imark = irbb->stmts[first_stmt_idx]; vassert(imark); vassert(imark->tag == Ist_IMark); vassert(imark->Ist.IMark.len == 0); imark->Ist.IMark.len = toUInt(dres.len); /* Print the resulting IR, if needed. */ if (vex_traceflags & VEX_TRACE_FE) { for (i = first_stmt_idx; i < irbb->stmts_used; i++) { vex_printf(" "); ppIRStmt(irbb->stmts[i]); vex_printf("\n"); } } /* If dis_instr_fn terminated the BB at this point, check it also filled in the irbb->next field. */ if (dres.whatNext == Dis_StopHere) { vassert(irbb->next != NULL); if (debug_print) { vex_printf(" "); vex_printf( "goto {"); ppIRJumpKind(irbb->jumpkind); vex_printf( "} "); ppIRExpr( irbb->next ); vex_printf( "\n"); } } /* Update the VexGuestExtents we are constructing. */ /* If vex_control.guest_max_insns is required to be < 100 and each insn is at max 20 bytes long, this limit of 5000 then seems reasonable since the max possible extent length will be 100 * 20 == 2000. */ vassert(vge->len[vge->n_used-1] < 5000); vge->len[vge->n_used-1] = toUShort(toUInt( vge->len[vge->n_used-1] + dres.len )); n_instrs++; if (debug_print) vex_printf("\n"); /* Advance delta (inconspicuous but very important :-) */ delta += (Long)dres.len; switch (dres.whatNext) { case Dis_Continue: vassert(irbb->next == NULL); if (n_instrs < vex_control.guest_max_insns) { /* keep going */ } else { /* We have to stop. */ irbb->next = IRExpr_Const( guest_word_type == Ity_I32 ? IRConst_U32(toUInt(guest_IP_bbstart+delta)) : IRConst_U64(guest_IP_bbstart+delta) ); goto done; } break; case Dis_StopHere: vassert(irbb->next != NULL); goto done; case Dis_Resteer: /* Check that we actually allowed a resteer .. */ vassert(resteerOK); vassert(irbb->next == NULL); /* figure out a new delta to continue at. */ vassert(resteerOKfn(callback_opaque,dres.continueAt)); delta = dres.continueAt - guest_IP_bbstart; /* we now have to start a new extent slot. */ vge->n_used++; vassert(vge->n_used <= 3); vge->base[vge->n_used-1] = dres.continueAt; vge->len[vge->n_used-1] = 0; n_resteers++; d_resteers++; if (0 && (n_resteers & 0xFF) == 0) vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n", n_resteers, d_resteers, dres.continueAt, delta); break; default: vpanic("bb_to_IR"); } } /*NOTREACHED*/ vassert(0); done: /* We're done. The only thing that might need attending to is that a self-checking preamble may need to be created. */ if (do_self_check) { UInt len2check, adler32; IRTemp tistart_tmp, tilen_tmp; vassert(vge->n_used == 1); len2check = vge->len[0]; if (len2check == 0) len2check = 1; adler32 = genericg_compute_adler32( (HWord)guest_code, len2check ); /* 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. */ tistart_tmp = newIRTemp(irbb->tyenv, guest_word_type); tilen_tmp = newIRTemp(irbb->tyenv, guest_word_type); irbb->stmts[selfcheck_idx+0] = IRStmt_Tmp(tistart_tmp, IRExpr_Const(guest_IP_bbstart_IRConst) ); irbb->stmts[selfcheck_idx+1] = IRStmt_Tmp(tilen_tmp, guest_word_type==Ity_I32 ? IRExpr_Const(IRConst_U32(len2check)) : IRExpr_Const(IRConst_U64(len2check)) ); irbb->stmts[selfcheck_idx+2] = IRStmt_Put( offB_TISTART, IRExpr_Tmp(tistart_tmp) ); irbb->stmts[selfcheck_idx+3] = IRStmt_Put( offB_TILEN, IRExpr_Tmp(tilen_tmp) ); irbb->stmts[selfcheck_idx+4] = IRStmt_Exit( IRExpr_Binop( Iop_CmpNE32, mkIRExprCCall( Ity_I32, 2/*regparms*/, "genericg_compute_adler32", #if defined(__powerpc__) && defined(__powerpc64__) (void*)((ULong*)(&genericg_compute_adler32))[0], #else &genericg_compute_adler32, #endif mkIRExprVec_2( mkIRExpr_HWord( (HWord)guest_code ), mkIRExpr_HWord( (HWord)len2check ) ) ), IRExpr_Const(IRConst_U32(adler32)) ), Ijk_TInval, guest_IP_bbstart_IRConst ); } return irbb; }