Add the infrastructure to test instruction emulations automatically.
The idea is that the instruction to be emulated is actually executed
on the hardware to be emulated, with the before and after state of the
hardware being captured and 'freeze-dried' into .dat files. The
emulation testing code then loads the before & after state from the
.dat file, emulates the instruction using the before state, and
compares the resulting state to the 'after' state. If they match, the
emulation is accurate, otherwise there is a problem.
The final format of the .dat files needs a bit more work; the plan is
to generalize them a bit and to convert the plain values to key-value pairs.
But I wanted to get this first pass committed.
This commit adds arm instruction emulation testing to the testsuite, along with
many initial .dat files.
It also fixes a bug in the llvm disassembler, where 32-bit thumb opcodes
were getting their upper & lower 16-bits reversed.
There is a new Instruction sub-class, that is intended to be loaded
from a .dat file rather than read from an executable. There is also a
new EmulationStateARM class, for handling the before & after states.
EmulationStates for other architetures can be added later when we
emulate their instructions.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@129832 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
index 9b8d07e..c4a6cfe 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -10,10 +10,12 @@
#include <stdlib.h>
#include "EmulateInstructionARM.h"
+#include "EmulationStateARM.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
#include "Plugins/Process/Utility/ARMDefines.h"
#include "Plugins/Process/Utility/ARMUtils.h"
@@ -12218,6 +12220,8 @@
{ 0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"},
// mul
{ 0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>" },
+
+ // subs pc, lr and related instructions
{ 0x0e10f000, 0x0210f000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,#<const> | <Rn>,#<const>" },
{ 0x0e10f010, 0x0010f000, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,<Rn>,<Rm{,<shift>}" },
@@ -12504,8 +12508,9 @@
{ 0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>" },
// mul
{ 0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>" },
+
+ // subs pc, lr and related instructions
{ 0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>" },
-
//----------------------------------------------------------------------
// RFE instructions *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE LDM.. Instructions in this table;
@@ -13193,16 +13198,7 @@
ARMOpcode *opcode_data;
if (m_opcode_mode == eModeThumb)
- {
- if (m_opcode.GetType() == Opcode::eType32)
- {
- uint16_t upper_bits = Bits32 (m_opcode.GetOpcode32(), 31, 16);
- uint16_t lower_bits = Bits32 (m_opcode.GetOpcode32(), 15, 0);
- uint32_t swapped = (lower_bits << 16) | upper_bits;
- m_opcode.SetOpcode32 (swapped);
- }
opcode_data = GetThumbOpcodeForInstruction (m_opcode.GetOpcode32());
- }
else if (m_opcode_mode == eModeARM)
opcode_data = GetARMOpcodeForInstruction (m_opcode.GetOpcode32());
else
@@ -13311,3 +13307,112 @@
return true;
}
+
+bool
+EmulateInstructionARM::TestEmulation (Stream *out_stream, FILE *test_file, ArchSpec &arch)
+{
+ if (!test_file)
+ {
+ out_stream->Printf ("TestEmulation: Missing test file.\n");
+ return false;
+ }
+
+ uint32_t test_opcode;
+ if (fscanf (test_file, "%x", &test_opcode) != 1)
+ {
+ out_stream->Printf ("Test Emulation: Error reading opcode from test file.\n");
+ return false;
+ }
+
+ char buffer[256];
+ fgets (buffer, 255, test_file); // consume the newline after reading the opcode.
+
+ SetAdvancePC (true);
+
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ m_opcode_mode = eModeARM;
+ m_opcode.SetOpcode32 (test_opcode);
+ }
+ else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ m_opcode_mode = eModeThumb;
+ if (test_opcode < 0x10000)
+ m_opcode.SetOpcode16 (test_opcode);
+ else
+ m_opcode.SetOpcode32 (test_opcode);
+
+ }
+ else
+ {
+ out_stream->Printf ("Test Emulation: Invalid arch.\n");
+ return false;
+ }
+
+
+ EmulationStateARM before_state;
+ EmulationStateARM after_state;
+
+ // Read Memory info & load into before_state
+ if (!fgets (buffer, 255, test_file))
+ {
+ out_stream->Printf ("Test Emulation: Error attempting to read from test file.\n");
+ return false;
+ }
+
+ if (strncmp (buffer, "Memory-Begin", 12) != 0)
+ {
+ out_stream->Printf ("Test Emulation: Cannot find Memory-Begin in test file.\n");
+ return false;
+ }
+
+ bool done = false;
+ while (!done)
+ {
+ if (fgets (buffer, 255, test_file))
+ {
+ if (strncmp (buffer, "Memory-End", 10) == 0)
+ done = true;
+ else
+ {
+ uint32_t addr;
+ uint32_t value;
+ if (sscanf (buffer, "%x %x", &addr, &value) == 2)
+ before_state.StoreToPseudoAddress ((addr_t) addr, (uint64_t) value, 4);
+ else
+ {
+ out_stream->Printf ("Test Emulation: Error attempting to sscanf address/value pair.\n");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ out_stream->Printf ("Test Emulation: Error attemping to read test file.\n");
+ return false;
+ }
+ }
+
+ if (!EmulationStateARM::LoadRegisterStatesFromTestFile (test_file, before_state, after_state))
+ {
+ out_stream->Printf ("Test Emulation: Error occurred while attempting to load the register data.\n");
+ return false;
+ }
+
+ SetBaton ((void *) &before_state);
+ SetCallbacks (&EmulationStateARM::ReadPseudoMemory,
+ &EmulationStateARM::WritePseudoMemory,
+ &EmulationStateARM::ReadPseudoRegister,
+ &EmulationStateARM::WritePseudoRegister);
+
+ bool success = EvaluateInstruction ();
+ if (!success)
+ {
+ out_stream->Printf ("Test Emulation: EvaluateInstruction() failed.\n");
+ return false;
+ }
+
+ success = before_state.CompareState (after_state);
+ return success;
+}
+
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
index d4d9670..49ade99 100644
--- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -148,6 +148,9 @@
virtual bool
EvaluateInstruction ();
+
+ virtual bool
+ TestEmulation (Stream *out_stream, FILE *test_file, ArchSpec &arch);
uint32_t
ArchVersion();
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
new file mode 100644
index 0000000..c3f363f
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -0,0 +1,428 @@
+//===-- EmulationStateARM.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulationStateARM.h"
+
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+EmulationStateARM::EmulationStateARM () :
+ m_gpr (),
+ m_vfp_regs (),
+ m_memory ()
+{
+ ClearPseudoRegisters();
+}
+
+EmulationStateARM::~EmulationStateARM ()
+{
+}
+
+bool
+EmulationStateARM::LoadPseudoRegistersFromFrame (StackFrame &frame)
+{
+ RegisterContext *reg_context = frame.GetRegisterContext().get();
+ Scalar value;
+ uint64_t reg_value64;
+ uint32_t reg_value32;
+
+ bool success = true;
+
+ for (int i = dwarf_r0; i < dwarf_r0 + 17; ++i)
+ {
+ uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ if (reg_context->ReadRegisterValue (internal_reg_num, value))
+ {
+ reg_value32 = (uint32_t) value.GetRawBits64 (0);
+ m_gpr[i - dwarf_r0] = reg_value32;
+ }
+ else
+ success = false;
+ }
+
+ for (int i = dwarf_s0; i < dwarf_s0 + 32; ++i)
+ {
+ uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ if (reg_context->ReadRegisterValue (internal_reg_num, value))
+ {
+ uint32_t idx = i - dwarf_s0;
+ reg_value32 = (uint32_t) value.GetRawBits64 (0);
+ m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2] = reg_value32;
+ }
+ else
+ success = false;
+ }
+
+ for (int i = dwarf_d0; i < dwarf_d0 + 32; ++i)
+ {
+ uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ if (reg_context->ReadRegisterValue (internal_reg_num, value))
+ {
+ uint32_t idx = i - dwarf_d0;
+ reg_value64 = value.GetRawBits64 (0);
+ if (i < 16)
+ m_vfp_regs.sd_regs[idx].d_reg = reg_value64;
+ else
+ m_vfp_regs.d_regs[idx - 16] = reg_value64;
+ }
+ else
+ success = false;
+ }
+
+ return success;
+}
+
+bool
+EmulationStateARM::StorePseudoRegisterValue (uint32_t reg_num, uint64_t value)
+{
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ m_gpr[reg_num - dwarf_r0] = (uint32_t) value;
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2] = (uint32_t) value;
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ {
+ m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg = value;
+ }
+ else
+ m_vfp_regs.d_regs[reg_num - dwarf_d16] = value;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+uint64_t
+EmulationStateARM::ReadPseudoRegisterValue (uint32_t reg_num, bool &success)
+{
+ uint64_t value = 0;
+ success = true;
+
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ value = m_gpr[reg_num - dwarf_r0];
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ value = m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2];
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ value = m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg;
+ else
+ value = m_vfp_regs.d_regs[reg_num - dwarf_d16];
+ }
+ else
+ success = false;
+
+ return value;
+}
+
+void
+EmulationStateARM::ClearPseudoRegisters ()
+{
+ for (int i = 0; i < 17; ++i)
+ m_gpr[i] = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.sd_regs[i].d_reg = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.d_regs[i] = 0;
+}
+
+void
+EmulationStateARM::ClearPseudoMemory ()
+{
+ m_memory.clear();
+}
+
+bool
+EmulationStateARM::StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size)
+{
+ if (size > 8)
+ return false;
+
+ if (size <= 4)
+ m_memory[p_address] = value;
+ else if (size == 8)
+ {
+ m_memory[p_address] = (value << 32) >> 32;
+ m_memory[p_address + 4] = value << 32;
+ }
+ return true;
+}
+
+uint32_t
+EmulationStateARM::ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success)
+{
+ std::map<lldb::addr_t,uint32_t>::iterator pos;
+ uint32_t ret_val = 0;
+
+ success = true;
+ pos = m_memory.find(p_address);
+ if (pos != m_memory.end())
+ ret_val = pos->second;
+ else
+ success = false;
+
+ return ret_val;
+}
+
+size_t
+EmulationStateARM::ReadPseudoMemory (void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ if (length <= 4)
+ {
+ uint32_t value = pseudo_state->ReadFromPseudoAddress (addr, length, success);
+ if (!success)
+ return 0;
+
+ *((uint32_t *) dst) = value;
+ }
+ else if (length == 8)
+ {
+ uint32_t value1 = pseudo_state->ReadFromPseudoAddress (addr, 4, success);
+ if (!success)
+ return 0;
+
+ uint32_t value2 = pseudo_state->ReadFromPseudoAddress (addr + 4, 4, success);
+ if (!success)
+ return 0;
+
+ uint64_t value64 = value2;
+ value64 = (value64 << 32) | value1;
+ *((uint64_t *) dst) = value64;
+ }
+ else
+ success = false;
+
+ if (success)
+ return length;
+
+ return 0;
+}
+
+size_t
+EmulationStateARM::WritePseudoMemory (void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ uint64_t value = *((uint64_t *) dst);
+ success = pseudo_state->StoreToPseudoAddress (addr, value, length);
+ if (success)
+ return length;
+
+ return 0;
+}
+
+bool
+EmulationStateARM::ReadPseudoRegister (void *baton,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t ®_value)
+{
+ if (!baton)
+ return false;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+
+ if (reg_kind == eRegisterKindGeneric)
+ {
+ switch (reg_num)
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ reg_num = dwarf_pc; break;
+ case LLDB_REGNUM_GENERIC_SP:
+ reg_num = dwarf_sp; break;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ reg_num = dwarf_cpsr; break;
+ case LLDB_REGNUM_GENERIC_RA:
+ reg_num = dwarf_lr; break;
+ default:
+ break;
+ }
+ }
+ reg_value = pseudo_state->ReadPseudoRegisterValue (reg_num, success);
+
+ return success;
+
+}
+
+bool
+EmulationStateARM::WritePseudoRegister (void *baton,
+ const EmulateInstruction::Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t reg_value)
+{
+ if (!baton)
+ return false;
+
+ if (reg_kind == eRegisterKindGeneric)
+ {
+ switch (reg_num)
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ reg_num = dwarf_pc; break;
+ case LLDB_REGNUM_GENERIC_SP:
+ reg_num = dwarf_sp; break;
+ case LLDB_REGNUM_GENERIC_FLAGS:
+ reg_num = dwarf_cpsr; break;
+ case LLDB_REGNUM_GENERIC_RA:
+ reg_num = dwarf_lr; break;
+ default:
+ break;
+ }
+ }
+
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ return pseudo_state->StorePseudoRegisterValue (reg_num, reg_value);
+}
+
+bool
+EmulationStateARM::LoadState (FILE *test_file)
+{
+ if (!test_file)
+ return false;
+
+ uint32_t num_regs;
+ uint32_t value32;
+ uint64_t value64;
+
+ /* Load general register state */
+ if (fscanf (test_file, "%d", &num_regs) != 1)
+ return false;
+
+
+ for (int i = 0; i < num_regs; ++i)
+ {
+ if (fscanf (test_file, "%x", &value32) == 1)
+ {
+ if (i < 17) // We only have 17 general registers, but if for some reason the file contains more
+ // we need to read them all, to get to the next set of register values.
+ m_gpr[i] = value32;
+ }
+ else
+ return false;
+ }
+
+ /* Load d register state */
+ if (fscanf (test_file, "%d", &num_regs) != 1)
+ return false;
+
+ for (int i = 0; i < num_regs; ++i)
+ {
+ if (fscanf (test_file, "%x", &value64) == 1)
+ {
+ if (i < 32)
+ {
+ if (i < 16)
+ m_vfp_regs.sd_regs[i].d_reg = value64;
+ else
+ m_vfp_regs.d_regs[i - 16] = value64;
+ }
+ }
+ else
+ return false;
+ }
+
+ /* Load s register state */
+ if (fscanf (test_file, "%d", &num_regs) != 1)
+ return false;
+
+ for (int i = 0; i < num_regs; ++i)
+ {
+ if (fscanf (test_file, "%x", &value32) == 1)
+ m_vfp_regs.sd_regs[i / 2].s_reg[i % 2] = value32;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+bool
+EmulationStateARM::LoadRegisterStatesFromTestFile (FILE *test_file,
+ EmulationStateARM &before_state,
+ EmulationStateARM &after_state)
+{
+ if (test_file)
+ {
+ if (before_state.LoadState (test_file))
+ return after_state.LoadState (test_file);
+ }
+
+ return false;
+}
+
+bool
+EmulationStateARM::CompareState (EmulationStateARM &other_state)
+{
+ bool match = true;
+
+ for (int i = 0; match && i < 17; ++i)
+ {
+ if (m_gpr[i] != other_state.m_gpr[i])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 16; ++i)
+ {
+ if (m_vfp_regs.sd_regs[i].s_reg[0] != other_state.m_vfp_regs.sd_regs[i].s_reg[0])
+ match = false;
+
+ if (m_vfp_regs.sd_regs[i].s_reg[1] != other_state.m_vfp_regs.sd_regs[i].s_reg[1])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 32; ++i)
+ {
+ if (i < 16)
+ {
+ if (m_vfp_regs.sd_regs[i].d_reg != other_state.m_vfp_regs.sd_regs[i].d_reg)
+ match = false;
+ }
+ else
+ {
+ if (m_vfp_regs.d_regs[i - 16] != other_state.m_vfp_regs.d_regs[i - 16])
+ match = false;
+ }
+ }
+
+ return match;
+}
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.h b/source/Plugins/Instruction/ARM/EmulationStateARM.h
new file mode 100644
index 0000000..8ddfbed
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.h
@@ -0,0 +1,105 @@
+//===-- lldb_EmulationStateARM.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulationStateARM_h_
+#define lldb_EmulationStateARM_h_
+
+#include <map>
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Opcode.h"
+
+namespace lldb_private {
+
+class EmulationStateARM {
+public:
+
+ EmulationStateARM ();
+
+ virtual
+ ~EmulationStateARM ();
+
+ bool
+ StorePseudoRegisterValue (uint32_t reg_num, uint64_t value);
+
+ uint64_t
+ ReadPseudoRegisterValue (uint32_t reg_num, bool &success);
+
+ bool
+ StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size);
+
+ uint32_t
+ ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success);
+
+ void
+ ClearPseudoRegisters ();
+
+ void
+ ClearPseudoMemory ();
+
+ bool
+ LoadPseudoRegistersFromFrame (StackFrame &frame);
+
+ bool
+ LoadState (FILE *test_file);
+
+ static bool
+ LoadRegisterStatesFromTestFile (FILE *test_file, EmulationStateARM &before_state, EmulationStateARM &after_state);
+
+ bool
+ CompareState (EmulationStateARM &other_state);
+
+ static size_t
+ ReadPseudoMemory (void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WritePseudoMemory (void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadPseudoRegister (void *baton,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t ®_value);
+
+ static bool
+ WritePseudoRegister (void *baton,
+ const EmulateInstruction::Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t reg_value);
+private:
+ uint32_t m_gpr[17];
+ struct sd_regs
+ {
+ union
+ {
+ uint32_t s_reg[2];
+ uint64_t d_reg;
+ } sd_regs[16]; // sregs 0 - 31 & dregs 0 - 15
+
+ uint64_t d_regs[16]; // dregs 16-31
+
+ } m_vfp_regs;
+
+ std::map<lldb::addr_t, uint32_t> m_memory; // Eventually will want to change uint32_t to a data buffer heap type.
+
+ DISALLOW_COPY_AND_ASSIGN (EmulationStateARM);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_EmulationStateARM_h_