From: Petar Jovanovic Date: Fri, 19 Oct 2012 14:55:58 +0000 (+0000) Subject: Add a proper support for several MIPS instructions that generate SigFPE. X-Git-Tag: svn/VALGRIND_3_9_0^2~220 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb2515a647ea77a4837444173474e74f6743a51c;p=thirdparty%2Fvalgrind.git Add a proper support for several MIPS instructions that generate SigFPE. This VEX change needs to be paired with r13059 on Valgrind. Add support to properly handle TEQ, ADD and SUB instructions that generate exceptions on MIPS platforms. git-svn-id: svn://svn.valgrind.org/vex/trunk@2554 --- diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c index 65700fc1b1..6813a63847 100644 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -2944,14 +2944,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); break; - case 0x20: /* ADD */ + case 0x20: /* ADD */ DIP("add r%d, r%d, r%d", rd, rs, rt); - { - t2 = newTemp(Ity_I32); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + /* dst = src0 + src1 + * if(sign(src0 ) != sign(src1 )) + * goto no overflow; + * if(sign(dst) == sign(src0 )) + * goto no overflow; + * # we have overflow! */ - assign(t2, binop(Iop_Add32, getIReg(rs), getIReg(rt))); - putIReg(rd, mkexpr(t2)); - } + assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt))); + assign(t1, binop(Iop_Xor32, getIReg(rs), getIReg(rt))); + assign(t2, unop(Iop_1Uto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)), + mkU32(0x80000000)))); + + assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs))); + assign(t4, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)), + mkU32(0x80000000)))); + + stmt(IRStmt_Exit(binop(Iop_CmpEQ32, + binop(Iop_Or32, mkexpr(t2), mkexpr(t4)), + mkU32(0)), + Ijk_SigFPE_IntOvf, + IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC)); + + putIReg(rd, mkexpr(t0)); break; case 0x1A: /* DIV */ @@ -3007,7 +3033,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x22: /* SUB */ DIP("sub r%d, r%d, r%d", rd, rs, rt); - ALU_PATTERN(Iop_Sub32); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + /* dst = src0 + (-1 * src1) + * if(sign(src0 ) != sign((-1 * src1) )) + * goto no overflow; + * if(sign(dst) == sign(src0 )) + * goto no overflow; + * # we have overflow! */ + + assign(t5, binop(Iop_Mul32, getIReg(rt), mkU32(-1))); + assign(t0, binop(Iop_Add32, getIReg(rs), mkexpr(t5))); + assign(t1, binop(Iop_Xor32, getIReg(rs), mkexpr(t5))); + assign(t2, unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)), + mkU32(0x80000000)))); + + assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs))); + assign(t4, unop(Iop_1Sto32, + binop(Iop_CmpNE32, + binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)), + mkU32(0x80000000)))); + + stmt(IRStmt_Exit(binop(Iop_CmpEQ32, + binop(Iop_Or32, mkexpr(t2), mkexpr(t4)), + mkU32(0)), + Ijk_SigFPE_IntOvf, + IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC)); + + putIReg(rd, mkexpr(t0)); break; case 0x23: /* SUBU */ @@ -3126,43 +3185,97 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, case 0x30: { /* TGE */ /*tge */ DIP("tge r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)), - Ijk_SigTRAP, - IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)), + Ijk_SigTRAP, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x31: { /* TGEU */ /*tgeu */ DIP("tgeu r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)), - Ijk_SigTRAP, - IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)), + Ijk_SigTRAP, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x32: { /* TLT */ /*tlt */ DIP("tlt r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)), - Ijk_SigTRAP, - IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)), + Ijk_SigTRAP, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x33: { /* TLTU */ /*tltu */ DIP("tltu r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)), - Ijk_SigTRAP, - IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)), + Ijk_SigTRAP, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x34: { /* TEQ */ /*teq */ DIP("teq r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)), - Ijk_SigTRAP, IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)), + Ijk_SigTRAP, IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x36: { /* TNE */ /*tne */ DIP("tne r%d, r%d %d", rs, rt, trap_code); - stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)), - Ijk_SigTRAP, - IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + if (trap_code == 7) + stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntDiv, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else if (trap_code == 6) + stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)), + Ijk_SigFPE_IntOvf, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); + else + stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)), + Ijk_SigTRAP, + IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC)); break; } case 0x0F: { @@ -3345,9 +3458,40 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, getIReg(rs), mkU32(0x0)))), imm); break; - case 0x08: /* ADDI TODO: Check this */ + case 0x08: /* ADDI */ DIP("addi r%d, r%d, %d", rt, rs, imm); - putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm)))); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + /* dst = src0 + sign(imm) + * if(sign(src0 ) != sign(imm )) + * goto no overflow; + * if(sign(dst) == sign(src0 )) + * goto no overflow; + * # we have overflow! */ + + assign(t0, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm)))); + assign(t1, binop(Iop_Xor32, getIReg(rs), mkU32(extend_s_16to32(imm)))); + assign(t2, unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)), + mkU32(0x80000000)))); + + assign(t3, binop(Iop_Xor32, mkexpr(t0), getIReg(rs))); + assign(t4, unop(Iop_1Sto32, + binop(Iop_CmpNE32, + binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)), + mkU32(0x80000000)))); + + stmt(IRStmt_Exit(binop(Iop_CmpEQ32, + binop(Iop_Or32, mkexpr(t2), mkexpr(t4)), + mkU32(0)), + Ijk_SigFPE_IntOvf, + IRConst_U32(guest_PC_curr_instr + 4), OFFB_PC)); + + putIReg(rt, mkexpr(t0)); break; case 0x09: /* ADDIU */ diff --git a/VEX/priv/host_mips_defs.c b/VEX/priv/host_mips_defs.c index 02f396799e..8eb93cb456 100644 --- a/VEX/priv/host_mips_defs.c +++ b/VEX/priv/host_mips_defs.c @@ -3284,20 +3284,22 @@ Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc, /* imm32/64 r31, $magic_number */ UInt trcval = 0; switch (i->Min.XAssisted.jk) { - case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break; - case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break; - //case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; - //case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break; - case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break; - case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break; - //case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; - case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break; - case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break; - case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break; - case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break; - //case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; - case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break; - case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break; + case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break; + case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break; + //case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; + //case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break; + case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break; + case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break; + //case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; + case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break; + case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break; + case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break; + case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break; + //case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; + case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break; + case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break; + case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break; + case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break; /* We don't expect to see the following being assisted. */ //case Ijk_Ret: //case Ijk_Call: diff --git a/VEX/priv/host_mips_isel.c b/VEX/priv/host_mips_isel.c index 7df8543dc1..82e4b5a03c 100644 --- a/VEX/priv/host_mips_isel.c +++ b/VEX/priv/host_mips_isel.c @@ -3049,6 +3049,8 @@ static void iselStmt(ISelEnv * env, IRStmt * stmt) case Ijk_NoRedir: case Ijk_SigBUS: case Ijk_SigTRAP: + case Ijk_SigFPE_IntDiv: + case Ijk_SigFPE_IntOvf: case Ijk_Sys_syscall: case Ijk_TInval: { @@ -3150,6 +3152,8 @@ static void iselNext ( ISelEnv* env, case Ijk_NoRedir: case Ijk_SigBUS: case Ijk_SigTRAP: + case Ijk_SigFPE_IntDiv: + case Ijk_SigFPE_IntOvf: case Ijk_Sys_syscall: case Ijk_TInval: { HReg r = iselWordExpr_R(env, next); diff --git a/VEX/priv/ir_defs.c b/VEX/priv/ir_defs.c index 8138d59730..0d0d151d5f 100644 --- a/VEX/priv/ir_defs.c +++ b/VEX/priv/ir_defs.c @@ -1217,27 +1217,29 @@ void ppIRPutI ( IRPutI* puti ) void ppIRJumpKind ( IRJumpKind kind ) { switch (kind) { - case Ijk_Boring: vex_printf("Boring"); break; - case Ijk_Call: vex_printf("Call"); break; - case Ijk_Ret: vex_printf("Return"); break; - case Ijk_ClientReq: vex_printf("ClientReq"); break; - case Ijk_Yield: vex_printf("Yield"); break; - case Ijk_EmWarn: vex_printf("EmWarn"); break; - case Ijk_EmFail: vex_printf("EmFail"); break; - case Ijk_NoDecode: vex_printf("NoDecode"); break; - case Ijk_MapFail: vex_printf("MapFail"); break; - case Ijk_TInval: vex_printf("Invalidate"); break; - case Ijk_NoRedir: vex_printf("NoRedir"); break; - case Ijk_SigTRAP: vex_printf("SigTRAP"); break; - case Ijk_SigSEGV: vex_printf("SigSEGV"); break; - case Ijk_SigBUS: vex_printf("SigBUS"); break; - case Ijk_Sys_syscall: vex_printf("Sys_syscall"); break; - case Ijk_Sys_int32: vex_printf("Sys_int32"); break; - case Ijk_Sys_int128: vex_printf("Sys_int128"); break; - case Ijk_Sys_int129: vex_printf("Sys_int129"); break; - case Ijk_Sys_int130: vex_printf("Sys_int130"); break; - case Ijk_Sys_sysenter: vex_printf("Sys_sysenter"); break; - default: vpanic("ppIRJumpKind"); + case Ijk_Boring: vex_printf("Boring"); break; + case Ijk_Call: vex_printf("Call"); break; + case Ijk_Ret: vex_printf("Return"); break; + case Ijk_ClientReq: vex_printf("ClientReq"); break; + case Ijk_Yield: vex_printf("Yield"); break; + case Ijk_EmWarn: vex_printf("EmWarn"); break; + case Ijk_EmFail: vex_printf("EmFail"); break; + case Ijk_NoDecode: vex_printf("NoDecode"); break; + case Ijk_MapFail: vex_printf("MapFail"); break; + case Ijk_TInval: vex_printf("Invalidate"); break; + case Ijk_NoRedir: vex_printf("NoRedir"); break; + case Ijk_SigTRAP: vex_printf("SigTRAP"); break; + case Ijk_SigSEGV: vex_printf("SigSEGV"); break; + case Ijk_SigBUS: vex_printf("SigBUS"); break; + case Ijk_SigFPE_IntDiv: vex_printf("SigFPE_IntDiv"); break; + case Ijk_SigFPE_IntOvf: vex_printf("SigFPE_IntOvf"); break; + case Ijk_Sys_syscall: vex_printf("Sys_syscall"); break; + case Ijk_Sys_int32: vex_printf("Sys_int32"); break; + case Ijk_Sys_int128: vex_printf("Sys_int128"); break; + case Ijk_Sys_int129: vex_printf("Sys_int129"); break; + case Ijk_Sys_int130: vex_printf("Sys_int130"); break; + case Ijk_Sys_sysenter: vex_printf("Sys_sysenter"); break; + default: vpanic("ppIRJumpKind"); } } diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index e210f8671a..3ab417a12a 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -1872,6 +1872,8 @@ typedef Ijk_SigTRAP, /* current instruction synths SIGTRAP */ Ijk_SigSEGV, /* current instruction synths SIGSEGV */ Ijk_SigBUS, /* current instruction synths SIGBUS */ + Ijk_SigFPE_IntDiv, /* current instruction synths SIGFPE - IntDiv */ + Ijk_SigFPE_IntOvf, /* current instruction synths SIGFPE - IntOvf */ /* Unfortunately, various guest-dependent syscall kinds. They all mean: do a syscall before continuing. */ Ijk_Sys_syscall, /* amd64 'syscall', ppc 'sc', arm 'svc #0' */ diff --git a/VEX/pub/libvex_trc_values.h b/VEX/pub/libvex_trc_values.h index 688f28ed3b..db2909b9d5 100644 --- a/VEX/pub/libvex_trc_values.h +++ b/VEX/pub/libvex_trc_values.h @@ -62,6 +62,12 @@ continuing */ #define VEX_TRC_JMP_SIGBUS 93 /* deliver SIGBUS before continuing */ +#define VEX_TRC_JMP_SIGFPE_INTDIV 97 /* deliver SIGFPE (integer divide + by zero) before continuing */ + +#define VEX_TRC_JMP_SIGFPE_INTOVF 99 /* deliver SIGFPE (integer overflow) + before continuing */ + #define VEX_TRC_JMP_EMWARN 63 /* deliver emulation warning before continuing */ #define VEX_TRC_JMP_EMFAIL 83 /* emulation fatal error; abort system */