Add EmulateTB() method to emulate "Table Branch Byte" and "Table Branch Halfword"
operations for Thumb2.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@125767 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/lldb/Core/EmulateInstruction.h b/include/lldb/Core/EmulateInstruction.h
index 917c6d7..4555bb9 100644
--- a/include/lldb/Core/EmulateInstruction.h
+++ b/include/lldb/Core/EmulateInstruction.h
@@ -153,6 +153,10 @@
// arg1 = immediate data or don't care
// arg2 = don't care
eContextSupervisorCall,
+
+ // Used when performing a MemU operation to read the PC-relative offset
+ // from an address.
+ eContextTableBranchReadMemory,
// Used when random bits are written into a register
// arg0 = target register kind
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index 9b1a16f..3660850 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -1831,6 +1831,87 @@
return true;
}
+// Table Branch Byte causes a PC-relative forward branch using a table of single byte offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the byte returned from the table.
+//
+// Table Branch Halfword causes a PC-relative forward branch using a table of single halfword offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the halfword returned from the table.
+// TBB, TBH
+bool
+EmulateInstructionARM::EmulateTB (ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ if is_tbh then
+ halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]);
+ else
+ halfwords = UInt(MemU[R[n]+R[m], 1]);
+ BranchWritePC(PC + 2*halfwords);
+#endif
+
+ bool success = false;
+ const uint32_t opcode = OpcodeAsUnsigned (&success);
+ if (!success)
+ return false;
+
+ uint32_t Rn; // the base register which contains the address of the table of branch lengths
+ uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
+ bool is_tbh; // true if table branch halfword
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ is_tbh = BitIsSet(opcode, 4);
+ if (Rn == 13 || BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // Read the address of the table from the operand register Rn.
+ // The PC can be used, in which case the table immediately follows this instruction.
+ uint32_t base =
+ Rn == 15 ? (ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success) + 4)
+ : ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success);
+ if (!success)
+ return false;
+
+ // the table index
+ uint32_t index = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success);
+ if (!success)
+ return false;
+
+ // the offsetted table address
+ addr_t addr = base + (is_tbh ? index*2 : index);
+
+ // PC-relative offset to branch forward
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextTableBranchReadMemory;
+ uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success);
+ if (!success)
+ return false;
+
+ const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+ if (!success)
+ return false;
+
+ // target address
+ addr_t target = pc + 4 + offset;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetModeAndImmediateSigned (eModeThumb, 4 + offset);
+
+ if (!BranchWritePC(context, target))
+ return false;
+
+ return true;
+}
+
// ADD <Rdn>, <Rm>
// where <Rdn> the destination register is also the first operand register
// and <Rm> is the second operand register.
@@ -4282,6 +4363,10 @@
{ 0xffffff87, 0x00004700, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
// compare and branch
{ 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
+ // table branch byte
+ { 0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"},
+ // table branch halfword
+ { 0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"},
//----------------------------------------------------------------------
// Data-processing instructions
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
index 0d2d243..bf79a26 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -384,6 +384,10 @@
bool
EmulateCB (ARMEncoding encoding);
+ // A8.6.226 TBB, TBH
+ bool
+ EmulateTB (ARMEncoding encoding);
+
// A8.6.6 ADD (register) -- Encoding T2
bool
EmulateAddRdnRm (ARMEncoding encoding);