From: Julian Seward Date: Wed, 16 Mar 2005 18:19:10 +0000 (+0000) Subject: Add a new kind of IR stmt: "instruction marks" (IRStmt_IMark), so as X-Git-Tag: svn/VALGRIND_3_0_1^2~288 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be1682ca4d672341f14780f8d520c503d6bf0408;p=thirdparty%2Fvalgrind.git Add a new kind of IR stmt: "instruction marks" (IRStmt_IMark), so as to support profiling. It is the responsibility of front ends (toIR.c) to generate these. For each instruction, the first IR stmt emitted should be an IMark, stating the guest address and length of the guest instruction represented by the IR that follows. All IR stmts following the IMark but before the next IMark are then assumed to 'belong to' the guest insn described by the first IMark. IMarks do not denote executable code and can be ignored at any point in the proceedings; they are an optional addition which help profiling-annotators to navigate the IR stmt stream. This commit adds IR level infrastructure for IMarks and IMark generation in the x86 front end. The amd64 and ppc32 front end are not yet done. git-svn-id: svn://svn.valgrind.org/vex/trunk@1046 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 9ea356599d..76d7c51d0f 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -246,6 +246,7 @@ IRBB* bbToIR_X86 ( UChar* x86code, Addr64 guest_next; Bool resteerOK; DisResult dres; + IRStmt* imark; static Int n_resteers = 0; Int d_resteers = 0; @@ -290,20 +291,41 @@ IRBB* bbToIR_X86 ( UChar* x86code, && vge->n_used < 3 ); + /* This is the %EIP of the instruction we're just about to deal + with. */ + guest_eip_curr_instr = guest_eip_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 + disInstr how long the instruction is, so just put in a zero + length and we'll fix it up later. */ + stmt( IRStmt_IMark( (Addr64)guest_eip_curr_instr, 0 )); + if (n_instrs > 0) { /* for the first insn, the dispatch loop will have set %EIP, but for all the others we have to do it ourselves. */ - stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_bbstart + delta)) ); + stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr)) ); } - guest_eip_curr_instr = guest_eip_bbstart + delta; - + /* Do the instruction. This may set insn_verbose to True, which + needs to be annulled. */ + size = 0; /* just in case disInstr doesn't set it */ dres = disInstr( resteerOK, chase_into_ok, delta, subarch_guest, &size, &guest_next ); insn_verbose = False; + /* 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 = size; + /* Print the resulting IR, if needed. */ if (vex_traceflags & VEX_TRACE_FE) { for (i = first_stmt_idx; i < irbb->stmts_used; i++) { diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 662af10683..1ba1af1d23 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -3372,6 +3372,11 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) addInstr(env, X86Instr_MFence(env->subarch)); return; + /* --------- INSTR MARK --------- */ + /* Doesn't generate any executable code ... */ + case Ist_IMark: + return; + /* --------- EXIT --------- */ case Ist_Exit: { X86RI* dst; diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 45f5975907..d7ffcdbc73 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -577,6 +577,10 @@ void ppIRJumpKind ( IRJumpKind kind ) void ppIRStmt ( IRStmt* s ) { switch (s->tag) { + case Ist_IMark: + vex_printf("IMark(0x%llx, %d)", s->Ist.IMark.addr, + s->Ist.IMark.len); + break; case Ist_Put: vex_printf( "PUT(%d) = ", s->Ist.Put.offset); ppIRExpr(s->Ist.Put.data); @@ -900,6 +904,13 @@ IRDirty* emptyIRDirty ( void ) { /* Constructors -- IRStmt */ +IRStmt* IRStmt_IMark ( Addr64 addr, Int len ) { + IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); + s->tag = Ist_IMark; + s->Ist.IMark.addr = addr; + s->Ist.IMark.len = len; + return s; +} IRStmt* IRStmt_Put ( Int off, IRExpr* data ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_Put; @@ -1102,6 +1113,8 @@ IRDirty* dopyIRDirty ( IRDirty* d ) IRStmt* dopyIRStmt ( IRStmt* s ) { switch (s->tag) { + case Ist_IMark: + return IRStmt_IMark(s->Ist.IMark.addr, s->Ist.IMark.len); case Ist_Put: return IRStmt_Put(s->Ist.Put.offset, dopyIRExpr(s->Ist.Put.data)); @@ -1612,6 +1625,7 @@ Bool isFlatIRStmt ( IRStmt* st ) if (di->mAddr && !isAtom(di->mAddr)) return False; return True; + case Ist_IMark: case Ist_MFence: return True; case Ist_Exit: @@ -1749,6 +1763,8 @@ void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts ) Int i; IRDirty* d; switch (stmt->tag) { + case Ist_IMark: + break; case Ist_Put: useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.data,def_counts); break; @@ -1889,6 +1905,12 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy ) IRDirty* d; IRTypeEnv* tyenv = bb->tyenv; switch (stmt->tag) { + case Ist_IMark: + /* Somewhat heuristic, but rule out totally implausible + instruction sizes. */ + if (stmt->Ist.IMark.len < 0 || stmt->Ist.IMark.len > 20) + sanityCheckFail(bb,stmt,"IRStmt.IMark.len: implausible"); + break; case Ist_Put: tcExpr( bb, stmt, stmt->Ist.Put.data, gWordTy ); if (typeOfIRExpr(tyenv,stmt->Ist.Put.data) == Ity_I1) diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index dc27ff3390..62a3b1fd23 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -359,6 +359,9 @@ static void flatten_Stmt ( IRBB* bb, IRStmt* st ) IRExpr *e1, *e2; IRDirty *d, *d2; switch (st->tag) { + case Ist_IMark: + addStmtToIRBB(bb, st); + break; case Ist_Put: if (isAtom(st->Ist.Put.data)) { /* optimisation to reduce the amount of heap wasted @@ -692,6 +695,9 @@ static void handle_gets_Stmt ( vassert(isAtom(st->Ist.PutI.data)); break; + case Ist_IMark: + break; + default: vex_printf("\n"); ppIRStmt(st); @@ -1440,6 +1446,9 @@ static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st ) return IRStmt_Dirty(d2); } + case Ist_IMark: + return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len); + case Ist_MFence: return IRStmt_MFence(); @@ -1628,6 +1637,7 @@ static void addUses_Stmt ( Bool* set, IRStmt* st ) for (i = 0; d->args[i] != NULL; i++) addUses_Expr(set, d->args[i]); return; + case Ist_IMark: case Ist_MFence: return; case Ist_Exit: @@ -2453,6 +2463,9 @@ Bool guestAccessWhichMightOverlapPutI ( getArrayBounds(pi->Ist.PutI.descr, &minoffP, &maxoffP); switch (s2->tag) { + case Ist_IMark: + return False; + case Ist_MFence: /* just be paranoid ... this should be rare. */ return True; @@ -2682,6 +2695,8 @@ static void deltaIRStmt ( IRStmt* st, Int delta ) Int i; IRDirty* d; switch (st->tag) { + case Ist_IMark: + break; case Ist_Put: deltaIRExpr(st->Ist.Put.data, delta); break; @@ -3067,6 +3082,7 @@ static void occCount_Stmt ( TmpInfo** env, IRStmt* st ) for (i = 0; d->args[i]; i++) occCount_Expr(env, d->args[i]); return; + case Ist_IMark: case Ist_MFence: return; case Ist_Exit: @@ -3199,6 +3215,8 @@ static IRStmt* tbSubst_Stmt ( TmpInfo** env, IRStmt* st ) st->Ist.Exit.jk, st->Ist.Exit.dst ); + case Ist_IMark: + return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len); case Ist_MFence: return IRStmt_MFence(); case Ist_Dirty: @@ -3590,6 +3608,7 @@ static Bool hasGetIorPutI ( IRBB* bb ) if (d->mFx != Ifx_None) vassert(isAtom(d->mAddr)); break; + case Ist_IMark: case Ist_MFence: break; case Ist_Exit: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index dd4a9def47..7c3405b076 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -837,6 +837,8 @@ IRDirty* unsafeIRDirty_1_N ( IRTemp dst, /* The possible kinds of statements are as follows: */ typedef enum { + Ist_IMark, /* instruction mark: describe addr/len of guest insn + whose IR follows */ Ist_Put, /* write guest state, fixed offset */ Ist_PutI, /* write guest state, run-time offset */ Ist_Tmp, /* assign value to temporary */ @@ -851,6 +853,10 @@ typedef struct _IRStmt { IRStmtTag tag; union { + struct { + Addr64 addr; + Int len; + } IMark; struct { Int offset; IRExpr* data; @@ -883,6 +889,7 @@ typedef } IRStmt; +extern IRStmt* IRStmt_IMark ( Addr64 addr, Int len ); extern IRStmt* IRStmt_Put ( Int off, IRExpr* data ); extern IRStmt* IRStmt_PutI ( IRArray* descr, IRExpr* ix, Int bias, IRExpr* data );