Added the start of opcode emulation for ARM instructions. This class is designed
to be fed 4 callbacks: read/write memory, and read/write registers. After this,
you can tell the object to read an instruction. This will cause the class to read
the PC, and read and instruction. Then you can emulate the instruction by calling
EvaluateInstruction. This will cause the class to figure out exactly what an opcode
does, and call the read/write mem/regs functions with actual values which allows one
to emulate an instruction without running a process, or it allows one to watch the
context information (the memory write is a pushing register 3 onto the stack at offset
12) so it can be used for generating call frame information. This way, in the future,
we will have one class that can be used to emulate instructions and generate our
unwind info from assembly.




git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@123998 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/Utility/EmulateInstructionARM.cpp b/source/Plugins/Process/Utility/EmulateInstructionARM.cpp
new file mode 100644
index 0000000..7055d5d
--- /dev/null
+++ b/source/Plugins/Process/Utility/EmulateInstructionARM.cpp
@@ -0,0 +1,299 @@
+//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulateInstructionARM.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// ARM constants used during decoding
+#define REG_RD          0
+#define LDM_REGLIST     1
+#define PC_REG          15
+#define PC_REGLIST_BIT  0x8000
+
+// ARM conditions
+#define COND_EQ     0x0
+#define COND_NE     0x1
+#define COND_CS     0x2
+#define COND_HS     0x2
+#define COND_CC     0x3
+#define COND_LO     0x3
+#define COND_MI     0x4
+#define COND_PL     0x5
+#define COND_VS     0x6
+#define COND_VC     0x7
+#define COND_HI     0x8
+#define COND_LS     0x9
+#define COND_GE     0xA
+#define COND_LT     0xB
+#define COND_GT     0xC
+#define COND_LE     0xD
+#define COND_AL     0xE
+#define COND_UNCOND 0xF
+
+
+#define MASK_CPSR_MODE_MASK	(0x0000001fu)
+#define MASK_CPSR_T         (1u << 5)
+#define MASK_CPSR_F         (1u << 6)
+#define MASK_CPSR_I         (1u << 7)
+#define MASK_CPSR_A         (1u << 8)
+#define MASK_CPSR_E         (1u << 9)
+#define MASK_CPSR_GE_MASK   (0x000f0000u)
+#define MASK_CPSR_J         (1u << 24)
+#define MASK_CPSR_Q         (1u << 27)
+#define MASK_CPSR_V         (1u << 28)
+#define MASK_CPSR_C         (1u << 29)
+#define MASK_CPSR_Z         (1u << 30)
+#define MASK_CPSR_N         (1u << 31)
+
+
+#define ARMv4	  (1u << 0)
+#define ARMv4T    (1u << 1)
+#define ARMv5T    (1u << 2)
+#define ARMv5TE   (1u << 3)
+#define ARMv5TEJ  (1u << 4)
+#define ARMv6	  (1u << 5)
+#define ARMv6K    (1u << 6)
+#define ARMv6T2   (1u << 7)
+#define ARMv7	  (1u << 8)
+#define ARMv8	  (1u << 8)
+#define ARMvAll   (0xffffffffu)
+
+typedef bool (*EmulateCallback) (EmulateInstructionARM *emulator);
+    
+
+typedef enum ARMEncoding
+{
+    eEncodingA1,
+    eEncodingA2,
+    eEncodingA3,
+    eEncodingA4,
+    eEncodingA5,
+    eEncodingT1,
+    eEncodingT2,
+    eEncodingT3,
+    eEncodingT4,
+    eEncodingT5,
+} ARMEncoding;
+
+
+typedef struct ARMOpcode
+{
+    uint32_t mask;
+    uint32_t value;
+    uint32_t variants;
+    ARMEncoding encoding;
+    const char *name;
+    EmulateCallback callback;
+};
+
+static bool 
+EmulateARMPushEncodingA1 (EmulateInstructionARM *emulator)
+{
+#if 0
+    // ARM pseudo code...
+    if (ConditionPassed())
+    {
+        EncodingSpecificOperations(); 
+        NullCheckIfThumbEE(13); 
+        address = SP - 4*BitCount(registers);
+
+        for (i = 0 to 14)
+        {
+            if (registers<i> == ’1’)
+            {
+                if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 
+                    MemA[address,4] = bits(32) UNKNOWN;
+                else 
+                    MemA[address,4] = R[i];
+                address = address + 4;
+            }
+        }
+
+        if (registers<15> == ’1’) // Only possible for encoding A1 or A2 
+            MemA[address,4] = PCStoreValue();
+        
+        SP = SP - 4*BitCount(registers);
+    }
+#endif
+
+    bool success = false;
+    const uint32_t opcode = emulator->OpcodeAsUnsigned (&success);
+    if (!success)
+        return false;
+
+    if (emulator->ConditionPassed())
+    {
+        const uint32_t addr_byte_size = emulator->GetAddressByteSize();
+        const addr_t sp = emulator->ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success);
+        if (!success)
+            return false;
+        const uint32_t registers = EmulateInstruction::UnsignedBits (opcode, 15, 0);
+        addr_t sp_offset = addr_byte_size * EmulateInstruction::BitCount (registers);
+        addr_t addr = sp - sp_offset;
+        uint32_t i;
+        
+        EmulateInstruction::Context context = { EmulateInstruction::eContextPushRegisterOnStack, eRegisterKindDWARF, 0, 0 };
+        for (i=0; i<15; ++i)
+        {
+            if (EmulateInstruction::BitIsSet (registers, 1u << i))
+            {
+                context.arg1 = dwarf_r0 + i;    // arg1 in the context is the DWARF register number
+                context.arg2 = addr - sp;       // arg2 in the context is the stack pointer offset
+                uint32_t reg_value = emulator->ReadRegisterUnsigned(eRegisterKindDWARF, context.arg1, 0, &success);
+                if (!success)
+                    return false;
+                if (!emulator->WriteMemoryUnsigned (context, addr, reg_value, addr_byte_size))
+                    return false;
+                addr += addr_byte_size;
+            }
+        }
+        
+        if (EmulateInstruction::BitIsSet (registers, 1u << 15))
+        {
+            context.arg1 = dwarf_pc;    // arg1 in the context is the DWARF register number
+            context.arg2 = addr - sp;       // arg2 in the context is the stack pointer offset
+            const uint32_t pc = emulator->ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success);
+            if (!success)
+                return false;
+            if (!emulator->WriteMemoryUnsigned (context, addr, pc + 8, addr_byte_size))
+                return false;
+        }
+        
+        context.type = EmulateInstruction::eContextAdjustStackPointer;
+        context.arg0 = eRegisterKindGeneric;
+        context.arg1 = LLDB_REGNUM_GENERIC_SP;
+        context.arg2 = sp_offset;
+    
+        if (!emulator->WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
+            return false;
+    }
+    return true;
+}
+
+static ARMOpcode g_arm_opcodes[] =
+{
+    { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, "PUSH<c> <registers>", EmulateARMPushEncodingA1 }
+};
+
+static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
+
+bool 
+EmulateInstructionARM::ReadInstruction ()
+{
+    bool success = false;
+    m_inst_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
+    if (success)
+    {
+        addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
+        if (success)
+        {
+            Context read_inst_context = {eContextReadOpcode, 0, 0};
+            if (m_inst_cpsr & MASK_CPSR_T)
+            {
+                m_inst_mode = eModeThumb;
+                uint32_t thumb_opcode = ReadMemoryUnsigned(read_inst_context, pc, 2, 0, &success);
+                
+                if (success)
+                {
+                    if ((m_inst.opcode.inst16 & 0xe000) != 0xe000 || ((m_inst.opcode.inst16 & 0x1800u) == 0))
+                    {
+                        m_inst.opcode_type = eOpcode16;
+                        m_inst.opcode.inst16 = thumb_opcode;
+                    }
+                    else
+                    {
+                        m_inst.opcode_type = eOpcode32;
+                        m_inst.opcode.inst32 = (thumb_opcode << 16) | ReadMemoryUnsigned(read_inst_context, pc + 2, 2, 0, &success);
+                    }
+                }
+            }
+            else
+            {
+                m_inst_mode = eModeARM;
+                m_inst.opcode_type = eOpcode32;
+                m_inst.opcode.inst32 = ReadMemoryUnsigned(read_inst_context, pc, 4, 0, &success);
+            }
+        }
+    }
+    if (!success)
+    {
+        m_inst_mode = eModeInvalid;
+        m_inst_pc = LLDB_INVALID_ADDRESS;
+    }
+    return success;
+}
+
+uint32_t
+EmulateInstructionARM::CurrentCond ()
+{
+    switch (m_inst_mode)
+    {
+    default:
+    case eModeInvalid:
+        break;
+
+    case eModeARM:
+        return UnsignedBits(m_inst.opcode.inst32, 31, 28);
+    
+    case eModeThumb:
+        return 0x0000000Eu; // Return always for now, we need to handl IT instructions later
+    }
+    return UINT32_MAX;  // Return invalid value
+}
+bool
+EmulateInstructionARM::ConditionPassed ()
+{
+    if (m_inst_cpsr == 0)
+        return false;
+
+    const uint32_t cond = CurrentCond ();
+    
+    if (cond == UINT32_MAX)
+        return false;
+    
+    bool result = false;
+    switch (UnsignedBits(cond, 3, 1))
+    {
+    case 0: result = (m_inst_cpsr & MASK_CPSR_Z) != 0; break;
+    case 1: result = (m_inst_cpsr & MASK_CPSR_C) != 0; break;
+    case 2: result = (m_inst_cpsr & MASK_CPSR_N) != 0; break;
+    case 3: result = (m_inst_cpsr & MASK_CPSR_V) != 0; break;
+    case 4: result = ((m_inst_cpsr & MASK_CPSR_C) != 0) && ((m_inst_cpsr & MASK_CPSR_Z) == 0); break;
+    case 5: 
+        {
+            bool n = (m_inst_cpsr & MASK_CPSR_N);
+            bool v = (m_inst_cpsr & MASK_CPSR_V);
+            result = n == v;
+        }
+        break;
+    case 6: 
+        {
+            bool n = (m_inst_cpsr & MASK_CPSR_N);
+            bool v = (m_inst_cpsr & MASK_CPSR_V);
+            result = n == v && ((m_inst_cpsr & MASK_CPSR_Z) == 0);
+        }
+        break;
+    case 7: 
+        result = true; 
+        break;
+    }
+
+    if (cond & 1)
+        result = !result;
+    return result;
+}
+
+
+bool
+EmulateInstructionARM::EvaluateInstruction ()
+{
+    return false;
+}