From: Julian Seward Date: Fri, 27 May 2011 13:20:56 +0000 (+0000) Subject: Add a field 'UChar delta' to IRStmt_IMark, and use it to carry around X-Git-Tag: svn/VALGRIND_3_7_0^2~71 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fa389dbb26827331eb811324da9e506768d8fbe4;p=thirdparty%2Fvalgrind.git Add a field 'UChar delta' to IRStmt_IMark, and use it to carry around the T bit for the instruction when the instruction is a ARM/Thumb. This more or less avoids introducing Thumb specific hacks in the IR, yet makes it possible to identify, from an IMark, whether it refers to a Thumb or ARM instruction. This is important for the GDB server integration to work properly on Thumb code. Patch from bug 214909 comment 99 (vex part). (Philippe Waroquiers, philippe.waroquiers@skynet.be) git-svn-id: svn://svn.valgrind.org/vex/trunk@2153 --- diff --git a/VEX/priv/guest_generic_bb_to_IR.c b/VEX/priv/guest_generic_bb_to_IR.c index 1e59c70e0d..4ce4e781ca 100644 --- a/VEX/priv/guest_generic_bb_to_IR.c +++ b/VEX/priv/guest_generic_bb_to_IR.c @@ -267,15 +267,30 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge, distinguishes ARM vs Thumb instructions. All instructions actually start on at least 2-aligned addresses. So we need to ignore the bottom bit of the insn address when forming the - IMark. For more details of this convention, see comments on - definition of guest_R15 in libvex_guest_arm.h. */ - addStmtToIRSB( irsb, - IRStmt_IMark( arch_guest == VexArchARM - ? (guest_IP_curr_instr & ~(Addr64)1) - : guest_IP_curr_instr, - 0 - ) - ); + IMark's address field, but put that bottom bit in the delta + field, so that comparisons against guest_R15T for Thumb can + be done correctly. By inspecting the delta field, + instruction processors can determine whether the instruction + was originally Thumb or ARM. For more details of this + convention, see comments on definition of guest_R15T in + libvex_guest_arm.h. */ + if (arch_guest == VexArchARM && (guest_IP_curr_instr & (Addr64)1)) { + /* Thumb insn => mask out the T bit, but put it in delta */ + addStmtToIRSB( irsb, + IRStmt_IMark(guest_IP_curr_instr & ~(Addr64)1, + 0, /* len */ + 1 /* delta */ + ) + ); + } else { + /* All other targets: store IP as-is, and set delta to zero. */ + addStmtToIRSB( irsb, + IRStmt_IMark(guest_IP_curr_instr, + 0, /* len */ + 0 /* delta */ + ) + ); + } /* for the first insn, the dispatch loop will have set %IP, but for all the others we have to do it ourselves. */ diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index ad12dec95c..566187ad34 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -1148,8 +1148,9 @@ void ppIRStmt ( IRStmt* s ) vex_printf("IR-NoOp"); break; case Ist_IMark: - vex_printf( "------ IMark(0x%llx, %d) ------", - s->Ist.IMark.addr, s->Ist.IMark.len); + vex_printf( "------ IMark(0x%llx, %d, %u) ------", + s->Ist.IMark.addr, s->Ist.IMark.len, + (UInt)s->Ist.IMark.delta); break; case Ist_AbiHint: vex_printf("====== AbiHint("); @@ -1604,11 +1605,12 @@ IRStmt* IRStmt_NoOp ( void ) static_closure.tag = Ist_NoOp; return &static_closure; } -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; +IRStmt* IRStmt_IMark ( Addr64 addr, Int len, UChar delta ) { + IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); + s->tag = Ist_IMark; + s->Ist.IMark.addr = addr; + s->Ist.IMark.len = len; + s->Ist.IMark.delta = delta; return s; } IRStmt* IRStmt_AbiHint ( IRExpr* base, Int len, IRExpr* nia ) { @@ -1871,7 +1873,9 @@ IRStmt* deepCopyIRStmt ( IRStmt* s ) s->Ist.AbiHint.len, deepCopyIRExpr(s->Ist.AbiHint.nia)); case Ist_IMark: - return IRStmt_IMark(s->Ist.IMark.addr, s->Ist.IMark.len); + return IRStmt_IMark(s->Ist.IMark.addr, + s->Ist.IMark.len, + s->Ist.IMark.delta); case Ist_Put: return IRStmt_Put(s->Ist.Put.offset, deepCopyIRExpr(s->Ist.Put.data)); @@ -3214,9 +3218,11 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy ) switch (stmt->tag) { case Ist_IMark: /* Somewhat heuristic, but rule out totally implausible - instruction sizes. */ + instruction sizes and deltas. */ if (stmt->Ist.IMark.len < 0 || stmt->Ist.IMark.len > 20) sanityCheckFail(bb,stmt,"IRStmt.IMark.len: implausible"); + if (stmt->Ist.IMark.delta > 1) + sanityCheckFail(bb,stmt,"IRStmt.IMark.delta: implausible"); break; case Ist_AbiHint: if (typeOfIRExpr(tyenv, stmt->Ist.AbiHint.base) != gWordTy) diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 5cf91dc456..b7746458a3 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -1997,7 +1997,9 @@ static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st ) } case Ist_IMark: - return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len); + return IRStmt_IMark(st->Ist.IMark.addr, + st->Ist.IMark.len, + st->Ist.IMark.delta); case Ist_NoOp: return IRStmt_NoOp(); @@ -4269,7 +4271,9 @@ static IRStmt* atbSubst_Stmt ( ATmpInfo* env, IRStmt* st ) st->Ist.Exit.dst ); case Ist_IMark: - return IRStmt_IMark(st->Ist.IMark.addr, st->Ist.IMark.len); + return IRStmt_IMark(st->Ist.IMark.addr, + st->Ist.IMark.len, + st->Ist.IMark.delta); case Ist_NoOp: return IRStmt_NoOp(); case Ist_MBE: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 2ec39acf7f..1479cd7382 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -104,7 +104,7 @@ One Vex IR translation for this code would be this: - ------ IMark(0x24F275, 7) ------ + ------ IMark(0x24F275, 7, 0) ------ t3 = GET:I32(0) # get %eax, a 32-bit integer t2 = GET:I32(12) # get %ebx, a 32-bit integer t1 = Add32(t3,t2) # addl @@ -147,7 +147,7 @@ This becomes (again ignoring condition code and instruction pointer updates): - ------ IMark(0x4000ABA, 3) ------ + ------ IMark(0x4000ABA, 3, 0) ------ t3 = Add32(GET:I32(0),0x4:I32) t2 = LDle:I32(t3) t1 = GET:I32(8) @@ -1894,12 +1894,27 @@ typedef the IRSB). Contains the address and length of the instruction. - ppIRStmt output: ------ IMark(, ) ------, - eg. ------ IMark(0x4000792, 5) ------, + It also contains a delta value. The delta must be + subtracted from a guest program counter value before + attempting to establish, by comparison with the address + and length values, whether or not that program counter + value refers to this instruction. For x86, amd64, ppc32, + ppc64 and arm, the delta value is zero. For Thumb + instructions, the delta value is one. This is because, on + Thumb, guest PC values (guest_R15T) are encoded using the + top 31 bits of the instruction address and a 1 in the lsb; + hence they appear to be (numerically) 1 past the start of + the instruction they refer to. IOW, guest_R15T on ARM + holds a standard ARM interworking address. + + ppIRStmt output: ------ IMark(, , ) ------, + eg. ------ IMark(0x4000792, 5, 0) ------, */ struct { Addr64 addr; /* instruction address */ Int len; /* instruction length */ + UChar delta; /* addr = program counter as encoded in guest state + - delta */ } IMark; /* META: An ABI hint, which says something about this @@ -2076,7 +2091,7 @@ typedef /* Statement constructors. */ extern IRStmt* IRStmt_NoOp ( void ); -extern IRStmt* IRStmt_IMark ( Addr64 addr, Int len ); +extern IRStmt* IRStmt_IMark ( Addr64 addr, Int len, UChar delta ); extern IRStmt* IRStmt_AbiHint ( IRExpr* base, Int len, IRExpr* nia ); extern IRStmt* IRStmt_Put ( Int off, IRExpr* data ); extern IRStmt* IRStmt_PutI ( IRRegArray* descr, IRExpr* ix, Int bias,