Support for disassembly of dsb, ldrex and strex.
Also print IT conditions for 32bit thumb operations.
Change-Id: Ie696dd7057730962efb791ba55041a2a70d1a975
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index 0472531..d4790ee 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -333,6 +333,21 @@
}
args << RegisterList(instr);
}
+ } else if ((op2 & 0x64) == 4) { // 00x x1xx
+ uint32_t op3 = (instr >> 23) & 3;
+ uint32_t op4 = (instr >> 20) & 3;
+ //uint32_t op5 = (instr >> 4) & 0xF;
+ ArmRegister Rn(instr, 16);
+ ArmRegister Rt(instr, 12);
+ uint32_t imm8 = instr & 0xFF;
+ if (op3 == 0 && op4 == 0) { // STREX
+ ArmRegister Rd(instr, 8);
+ opcode << "strex";
+ args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
+ } else if (op3 == 0 && op4 == 1) { // LDREX
+ opcode << "ldrex";
+ args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]";
+ }
} else if ((op2 & 0x60) == 0x20) { // 01x xxxx
// Data-processing (shifted register)
// |111|1110|0000|0|0000|1111|1100|0000|0000|
@@ -409,6 +424,42 @@
uint32_t op3 = (instr >> 20) & 0x3F;
uint32_t coproc = (instr >> 8) & 0xF;
uint32_t op4 = (instr >> 4) & 0x1;
+ if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) || // 00x1x
+ (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) { // 001xxx, 01xxxx
+ // Extension register load/store instructions
+ // |111|1|110|00000|0000|1111|110|000000000|
+ // |5 3|2|109|87654|3 0|54 2|10 |87 54 0|
+ // |---|-|---|-----|----|----|---|---------|
+ // |332|2|222|22222|1111|1111|110|000000000|
+ // |1 9|8|765|43210|9 6|54 2|10 |87 54 0|
+ // |---|-|---|-----|----|----|---|---------|
+ // |111|T|110| op3 | Rn | |101| |
+ // 111 0 110 01001 0011 0000 101 000000011 - ec930a03
+ if (op3 == 9 || op3 == 0xD) { // VLDM
+ // 1110 110 PUDW1 nnnn dddd 101S iiii iiii
+ uint32_t P = (instr >> 24) & 1;
+ uint32_t U = (instr >> 23) & 1;
+ uint32_t D = (instr >> 22) & 1;
+ uint32_t W = (instr >> 21) & 1;
+ uint32_t S = (instr >> 8) & 1;
+ ArmRegister Rn(instr, 16);
+ uint32_t Vd = (instr >> 12) & 0xF;
+ uint32_t imm8 = instr & 0xFF;
+ uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4)));
+ if (P == 0 && U == 0 && W == 0) {
+ // TODO: 64bit transfers between ARM core and extension registers.
+ } else if (P == 0 && U == 1 && Rn.r == 13) { // VPOP
+ opcode << "vpop" << (S == 0 ? ".f64" : ".f32");
+ args << d << " .. " << (d + imm8);
+ } else if (P == 1 && W == 0) { // VLDR
+ opcode << "vldr" << (S == 0 ? ".f64" : ".f32");
+ args << d << ", [" << Rn << ", #" << imm8 << "]";
+ } else { // VLDM
+ opcode << "vldm" << (S == 0 ? ".f64" : ".f32");
+ args << Rn << ", " << d << " .. " << (d + imm8);
+ }
+ }
+ }
if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0
if ((coproc & 0xE) == 0xA) {
// VFP data-processing instructions
@@ -576,6 +627,14 @@
DumpCond(opcode, cond);
opcode << ".w";
DumpBranchTarget(args, instr_ptr + 4, imm32);
+ } else if (op2 == 0x3B) {
+ // Miscellaneous control instructions
+ uint32_t op5 = (instr >> 4) & 0xF;
+ switch (op5) {
+ case 4: opcode << "dsb"; break;
+ case 5: opcode << "dmb"; break;
+ case 6: opcode << "isb"; break;
+ }
}
break;
case 2:
@@ -753,6 +812,13 @@
default:
break;
}
+
+ // Apply any IT-block conditions to the opcode if necessary.
+ if (!it_conditions_.empty()) {
+ opcode << it_conditions_.back();
+ it_conditions_.pop_back();
+ }
+
os << StringPrintf("\t\t\t%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
return 4;
}
@@ -890,6 +956,12 @@
default:
break;
}
+ } else if ((instr & 0xF800) == 0xA800) {
+ // Generate SP-relative address
+ ThumbRegister rd(instr, 8);
+ int imm8 = instr & 0xFF;
+ opcode << "add";
+ args << rd << ", sp, #" << (imm8 << 2);
} else if ((instr & 0xF000) == 0xB000) {
// Miscellaneous 16-bit instructions
uint16_t opcode2 = (instr >> 5) & 0x7F;