Dealt with undefined instr's properly
git-svn-id: svn://svn.valgrind.org/vex/trunk@643 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-arm/toIR.c b/priv/guest-arm/toIR.c
index f5c68d1..323d72b 100644
--- a/priv/guest-arm/toIR.c
+++ b/priv/guest-arm/toIR.c
@@ -767,8 +767,6 @@
/* Condition codes, using the ARM encoding. */
-// CAB: Just used for debugging printouts ?
-// yes, only for debugging
static HChar* name_ARMCondcode ( ARMCondcode cond )
{
switch (cond) {
@@ -817,7 +815,7 @@
ARM ARM A5-48
*/
static
-void dis_loadstore_mult ( theInstr )
+Bool dis_loadstore_mult ( theInstr )
{
UChar flags = (theInstr >> 20) & 0x1F; // theInstr[24:20]
UChar Rn_addr = (theInstr >> 16) & 0xF;
@@ -837,6 +835,7 @@
UInt n_bytes=0;
UInt tmp_reg = reg_list;
UInt reg_idx, offset;
+ Bool decode_ok = True;
while (tmp_reg > 0) { // Count num bits in reg_list => num_bytes
if (tmp_reg & 1) { n_bytes += 4; }
@@ -868,8 +867,8 @@
break;
default:
- vpanic("dis_loadstore_mult(ARM)");
- return;
+ vex_printf("dis_loadstore_mult(ARM): No such case: 0x%x", PU);
+ return False;
}
if (W==1) {
@@ -895,8 +894,10 @@
if (L==1) { // LOAD Ri, (start_addr + offset)
- // CAB: TODO
- if (Rn_addr == reg_idx && W==1) {} // Undefined! - See ARM ARM A4-31
+ if (Rn_addr == reg_idx && W==1) { // Undefined - ARM ARM A4-31
+ decode_ok=False;
+ break;
+ }
assign( data, loadLE(Ity_I32, binop(Iop_Add32,
mkexpr(start_addr), mkU32(offset))) );
@@ -909,12 +910,13 @@
} else { // STORE Ri, (start_addr + offset)
// ARM ARM A4-85 (Operand restrictions)
- if (reg_idx == Rn_addr && W==1) { // Rn in list && writeback
- if (offset==0) { // lowest reg in reg_list: Rn_orig is stored
- storeLE( mkexpr(start_addr), mkexpr(Rn_orig) );
- } else { // Undefined! - See ARM ARM A4-85
- // CAB TODO
+ if (reg_idx == Rn_addr && W==1) { // Rn in reg_list && writeback
+ if (offset != 0) { // Undefined - See ARM ARM A4-85
+ decode_ok=False;
+ break;
}
+ // is lowest reg in reg_list: store Rn_orig
+ storeLE( mkexpr(start_addr), mkexpr(Rn_orig) );
} else {
storeLE( binop(Iop_Add32, mkexpr(start_addr), mkU32(offset) ),
getIReg(reg_idx) );
@@ -926,7 +928,7 @@
// CAB TODO:
// IR assert( end_addr == (start_addr + offset) - 8 )
- return;
+ return decode_ok;
}
@@ -937,7 +939,7 @@
ARM ARM A5-18
*/
static
-void dis_loadstore_w_ub ( theInstr )
+Bool dis_loadstore_w_ub ( theInstr )
{
UChar is_reg = (theInstr >> 25) & 0x1; // immediate | register offset/index
UInt flags = (theInstr >> 20) & 0x3F; // theInstr[25:20]
@@ -976,14 +978,11 @@
if (Rn_addr == 15) {
if (P==1 && W==0) { // offset addressing: Rn not updated
- // CAB: This right?
- assign( Rn, binop(Iop_And32, mkexpr(Rn), mkU32(8)) );
- } else { // Unpredictable: ARM ARM A5-29
// CAB TODO
- //illegal instruction exception
-
-// goto decode_failure;
-
+ // CAB: This right?
+// assign( Rn, binop(Iop_And32, mkexpr(Rn), mkU32(8)) );
+ } else { // Unpredictable: ARM ARM A5-29
+ return False;
}
}
@@ -998,9 +997,9 @@
Retrieve address to load/store
*/
if (is_reg) {
- // CAB TODO
- if (Rm_addr == 15) {} // Unpredictable: ARM ARM A5-27
- if (Rm_addr == Rn_addr) {} // Unpredictable: ARM ARM A5-27
+ if (Rm_addr == 15 || Rm_addr == Rn_addr) { // Unpredictable: ARM ARM A5-27
+ return False;
+ }
assign( Rm, getIReg(Rm_addr) );
@@ -1137,10 +1136,11 @@
if ( Rd_addr == 15 && !(P == 0 && W==1)) { // R15 && not unprivileged...
+ // CAB: TODO
// assuming architecture < 5: See ARM ARM A4-28
- putIReg( Rd_addr, binop(Iop_And32, mkexpr(tmp), mkU32(0xFFFFFFFC)) );
+// putIReg( Rd_addr, binop(Iop_And32, mkexpr(tmp), mkU32(0xFFFFFFFC)) );
} else {
- putIReg( Rd_addr, mkexpr(tmp) );
+// putIReg( Rd_addr, mkexpr(tmp) );
}
}
@@ -1153,6 +1153,7 @@
storeLE( mkexpr(addr), getIReg(Rd_addr) );
}
}
+ return True;
}
@@ -1167,7 +1168,7 @@
carry = carry_out[0]
*/
static
-IRExpr* dis_shift( UInt theInstr, IRTemp* carry_out )
+IRExpr* dis_shift( Bool* decode_ok, UInt theInstr, IRTemp* carry_out )
{
UChar Rn_addr = (theInstr >> 16) & 0xF;
UChar Rd_addr = (theInstr >> 12) & 0xF;
@@ -1189,10 +1190,13 @@
assign(oldFlagC, mk_armg_calculate_flags_c());
switch (shift_op) {
- case 0x0: case 0x8: case 0x1: op = Iop_Shl32; break;
- case 0x2: case 0xA: case 0x3: op = Iop_Shr32; break;
- case 0x4: case 0xC: case 0x5: op = Iop_Sar32; break;
- default: vpanic("dis_shift"); break;
+ case 0x0: case 0x8: case 0x1: op = Iop_Shl32; break;
+ case 0x2: case 0xA: case 0x3: op = Iop_Shr32; break;
+ case 0x4: case 0xC: case 0x5: op = Iop_Sar32; break;
+ default:
+ vex_printf("dis_shift(arm): No such case: 0x%x\n", shift_op);
+ *decode_ok = False;
+ return mkU32(0);
}
@@ -1201,7 +1205,9 @@
if (Rd_addr == 15 || Rm_addr == 15 || Rn_addr == 15 || Rs_addr == 15) {
// Unpredictable (ARM ARM A5-10)
- // CAB TODO
+ vex_printf("dis_shift(arm): Unpredictable: R15 used in instr\n");
+ *decode_ok = False;
+ return mkU32(0);
}
assign( Rs, getIReg((theInstr >> 8) & 0xF) );
@@ -1232,7 +1238,8 @@
break;
default:
vex_printf("dis_shift(arm): Reg shift: No such case: 0x%x\n", shift_op);
- vpanic("dis_shift(ARM): Reg shift");
+ *decode_ok = False;
+ return mkU32(0);
}
expr = IRExpr_Mux0X(
@@ -1278,7 +1285,8 @@
break;
default:
vex_printf("dis_shift(arm): Imm shift: No such case: 0x%x\n", shift_op);
- vpanic("dis_shift(ARM): Imm shift");
+ *decode_ok = False;
+ return mkU32(0);
}
} else {
expr = binop(op, mkexpr(Rm), mkU8(shift_imm));
@@ -1297,7 +1305,7 @@
ARM ARM A5-15,16,17
*/
static
-IRExpr* dis_rotate ( UInt theInstr, IRTemp* carry_out )
+IRExpr* dis_rotate ( Bool* decode_ok, UInt theInstr, IRTemp* carry_out )
{
UChar Rn_addr = (theInstr >> 16) & 0xF;
UChar Rd_addr = (theInstr >> 12) & 0xF;
@@ -1321,7 +1329,8 @@
if (Rd_addr == 15 || Rm_addr == 15 || Rn_addr == 15 || Rs_addr == 15) {
// Unpredictable (ARM ARM A5-10)
- // CAB TODO
+ *decode_ok = False;
+ return mkU32(0);
}
assign( Rs, getIReg((theInstr >> 8) & 0xF) ); // instr[11:8]
@@ -1405,7 +1414,7 @@
Returns <shifter_operand> expression
*/
static
-IRExpr* dis_shifter_op ( UInt theInstr, IRTemp* carry_out)
+IRExpr* dis_shifter_op ( Bool *decode_ok, UInt theInstr, IRTemp* carry_out)
{
UChar is_immed = (theInstr >> 25) & 1; // immediate / register shift
UChar shift_op = (theInstr >> 4) & 0xF; // second byte
@@ -1413,8 +1422,6 @@
UInt imm;
IRTemp oldFlagC = newTemp(Ity_I32);
- // CAB TODO: Check what can do with R15... strict limits apply (ARM A5-9)
-
if (is_immed) { // ARM ARM A5-2
vex_printf("shifter_op: imm\n");
@@ -1438,11 +1445,16 @@
switch (shift_op) {
case 0x0: case 0x8: case 0x1:
case 0x2: case 0xA: case 0x3:
- case 0x4: case 0xC: case 0x5: return dis_shift(theInstr, carry_out);
- case 0x6: case 0xE: case 0x7: return dis_rotate(theInstr, carry_out);
+ case 0x4: case 0xC: case 0x5:
+ return dis_shift( decode_ok, theInstr, carry_out );
+
+ case 0x6: case 0xE: case 0x7:
+ return dis_rotate( decode_ok, theInstr, carry_out );
+
default: // Error: Any other value shouldn't be here.
- vpanic("dis_shifter_op(ARM)");
- return mkexpr(0);
+ *decode_ok = False;
+ vex_printf("dis_shifter_op(arm): shift: No such case: 0x%x\n", shift_op);
+ return mkU32(0);
}
}
}
@@ -1454,7 +1466,7 @@
/* -------------- Helper for DPI's. --------------
*/
static
-void dis_dataproc ( UInt theInstr )
+Bool dis_dataproc ( UInt theInstr )
{
UChar opc = (theInstr >> 21) & 0xF;
UChar set_flags = (theInstr >> 20) & 1;
@@ -1466,8 +1478,11 @@
IRTemp carry_out = newTemp(Ity_I32);
IROp op = ARMG_CC_OP_LOGIC;
Bool check_r15 = True;
+ Bool decode_ok = True;
- assign( shifter_op, dis_shifter_op( theInstr, &carry_out ) );
+ assign( shifter_op, dis_shifter_op( &decode_ok, theInstr, &carry_out ) );
+ if (!decode_ok) return False;
+
assign( Rd, getIReg(Rd_addr) );
assign( Rn, getIReg(Rn_addr) );
@@ -1500,9 +1515,9 @@
op = ARMG_CC_OP_ADD;
break;
- case 0x5: // x ADC
- case 0x6: // x SBC
- case 0x7: // x RSC
+ case 0x5: // ADC - Unimplemented
+ case 0x6: // SBC - Unimplemented
+ case 0x7: // RSC - Unimplemented
goto decode_failure;
case 0x8: // TST
@@ -1556,17 +1571,15 @@
default:
decode_failure:
- /* All decode failures end up here. */
- vex_printf("dis_dataproc(arm): unhandled instruction: 0x%x\n", theInstr);
- vpanic("armToIR: unimplemented insn");
+ vex_printf("dis_dataproc(arm): unhandled opcode: 0x%x\n", opc);
+ return False;
}
if (set_flags) {
if ( check_r15 && Rd_addr == 15) { // dest reg == PC
// CPSR = SPSR: Unpredictable in User | System mode (no SPSR!)
- // Unpredictable: Only supporting user mode.
- // CAB TODO
-
+ // Unpredictable: We're only supporting user mode...
+ decode_ok = False;
} else {
if (op == ARMG_CC_OP_LOGIC) {
setFlags_DEP1_DEP2( op, Rd, carry_out );
@@ -1575,6 +1588,7 @@
}
}
}
+ return decode_ok;
}
@@ -1604,7 +1618,6 @@
}
-// whatNext = Dis_StopHere;
@@ -1646,6 +1659,8 @@
// Int am_sz, d_sz;
DisResult whatNext = Dis_Continue;
UInt theInstr;
+ Bool decode_OK = True;
+
/* At least this is simple on ARM: insns are all 4 bytes long, and
4-aligned. So just fish the whole thing out of memory right now
@@ -1813,7 +1828,7 @@
case 0x7:
if (opc_tmp == 0x1) { // software breakpoint
- if (cond != 0xE) { goto decode_failure; } // (unpredictable ARM ARM A3-4)
+ if (cond != 0xE) goto decode_failure; // (unpredictable ARM ARM A3-4)
goto decode_failure;
}
break;
@@ -1829,7 +1844,7 @@
case 0x2:
case 0x3:
- if ((opc1 & 0xFB) == 0x30) goto decode_failure; // 0011 0x00 - (undefined)
+ if ((opc1 & 0xFB) == 0x30) goto decode_failure; // Undefined - ARM ARM A3-2
/*
A lonely 'MOV imm to status reg':
@@ -1843,7 +1858,7 @@
(if we get here, it's a valid dpi)
*/
vex_printf("OPCODE: DPI\n");
- dis_dataproc( theInstr );
+ if (!dis_dataproc( theInstr )) { goto decode_failure; }
break;
@@ -1851,11 +1866,10 @@
Load/Store word | unsigned byte
*/
case 0x6: case 0x7: // LOAD/STORE reg offset
- if ((opc2 & 0x1) == 0x1) { // Undefined: ARM ARM A3-2
- // CAB TODO (what todo?!)
- }
+ if ((opc2 & 0x1) == 0x1) goto decode_failure; // Undefined - ARM ARM A3-2
+
case 0x4: case 0x5: // LOAD/STORE imm offset
- dis_loadstore_w_ub(theInstr);
+ if (!dis_loadstore_w_ub(theInstr)) { goto decode_failure; }
break;
/*
@@ -1863,7 +1877,7 @@
*/
case 0x8: case 0x9:
vex_printf("OPCODE: LOAD/STORE mult\n");
- dis_loadstore_mult(theInstr);
+ if (!dis_loadstore_mult(theInstr)) { goto decode_failure; }
break;