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
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. */
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(");
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 ) {
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));
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)
}
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();
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:
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
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)
the IRSB). Contains the address and length of the
instruction.
- ppIRStmt output: ------ IMark(<addr>, <len>) ------,
- 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(<addr>, <len>, <delta>) ------,
+ 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
/* 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,