summaryrefslogtreecommitdiffstats
path: root/include/lldb/Core/EmulateInstruction.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/lldb/Core/EmulateInstruction.h')
-rw-r--r--include/lldb/Core/EmulateInstruction.h641
1 files changed, 641 insertions, 0 deletions
diff --git a/include/lldb/Core/EmulateInstruction.h b/include/lldb/Core/EmulateInstruction.h
new file mode 100644
index 0000000..08b97e4
--- /dev/null
+++ b/include/lldb/Core/EmulateInstruction.h
@@ -0,0 +1,641 @@
+//===-- EmulateInstruction.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_EmulateInstruction_h_
+#define lldb_EmulateInstruction_h_
+
+#include <string>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/Opcode.h"
+#include "lldb/Core/RegisterValue.h"
+
+//----------------------------------------------------------------------
+/// @class EmulateInstruction EmulateInstruction.h "lldb/Core/EmulateInstruction.h"
+/// @brief A class that allows emulation of CPU opcodes.
+///
+/// This class is a plug-in interface that is accessed through the
+/// standard static FindPlugin function call in the EmulateInstruction
+/// class. The FindPlugin takes a target triple and returns a new object
+/// if there is a plug-in that supports the architecture and OS. Four
+/// callbacks and a baton are provided. The four callbacks are read
+/// register, write register, read memory and write memory.
+///
+/// This class is currently designed for these main use cases:
+/// - Auto generation of Call Frame Information (CFI) from assembly code
+/// - Predicting single step breakpoint locations
+/// - Emulating instructions for breakpoint traps
+///
+/// Objects can be asked to read an instruction which will cause a call
+/// to the read register callback to get the PC, followed by a read
+/// memory call to read the opcode. If ReadInstruction () returns true,
+/// then a call to EmulateInstruction::EvaluateInstruction () can be
+/// made. At this point the EmulateInstruction subclass will use all of
+/// the callbacks to emulate an instruction.
+///
+/// Clients that provide the callbacks can either do the read/write
+/// registers/memory to actually emulate the instruction on a real or
+/// virtual CPU, or watch for the EmulateInstruction::Context which
+/// is context for the read/write register/memory which explains why
+/// the callback is being called. Examples of a context are:
+/// "pushing register 3 onto the stack at offset -12", or "adjusting
+/// stack pointer by -16". This extra context allows the generation of
+/// CFI information from assembly code without having to actually do
+/// the read/write register/memory.
+///
+/// Clients must be prepared that not all instructions for an
+/// Instruction Set Architecture (ISA) will be emulated.
+///
+/// Subclasses at the very least should implement the instructions that
+/// save and restore registers onto the stack and adjustment to the stack
+/// pointer. By just implementing a few instructions for an ISA that are
+/// the typical prologue opcodes, you can then generate CFI using a
+/// class that will soon be available.
+///
+/// Implementing all of the instructions that affect the PC can then
+/// allow single step prediction support.
+///
+/// Implementing all of the instructions allows for emulation of opcodes
+/// for breakpoint traps and will pave the way for "thread centric"
+/// debugging. The current debugging model is "process centric" where
+/// all threads must be stopped when any thread is stopped; when
+/// hitting software breakpoints we must disable the breakpoint by
+/// restoring the original breakpoint opcde, single stepping and
+/// restoring the breakpoint trap. If all threads were allowed to run
+/// then other threads could miss the breakpoint.
+///
+/// This class centralizes the code that usually is done in separate
+/// code paths in a debugger (single step prediction, finding save
+/// restore locations of registers for unwinding stack frame variables)
+/// and emulating the intruction is just a bonus.
+//----------------------------------------------------------------------
+
+namespace lldb_private {
+
+class EmulateInstruction :
+ public PluginInterface
+{
+public:
+
+ static EmulateInstruction*
+ FindPlugin (const ArchSpec &arch,
+ InstructionType supported_inst_type,
+ const char *plugin_name);
+
+ enum ContextType
+ {
+ eContextInvalid = 0,
+ // Read an instruciton opcode from memory
+ eContextReadOpcode,
+
+ // Usually used for writing a register value whose source value is an
+ // immediate
+ eContextImmediate,
+
+ // Exclusively used when saving a register to the stack as part of the
+ // prologue
+ eContextPushRegisterOnStack,
+
+ // Exclusively used when restoring a register off the stack as part of
+ // the epilogue
+ eContextPopRegisterOffStack,
+
+ // Add or subtract a value from the stack
+ eContextAdjustStackPointer,
+
+ // Adjust the frame pointer for the current frame
+ eContextSetFramePointer,
+
+ // Add or subtract a value from a base address register (other than SP)
+ eContextAdjustBaseRegister,
+
+ // Add or subtract a value from the PC or store a value to the PC.
+ eContextAdjustPC,
+
+ // Used in WriteRegister callbacks to indicate where the
+ eContextRegisterPlusOffset,
+
+ // Used in WriteMemory callback to indicate where the data came from
+ eContextRegisterStore,
+
+ eContextRegisterLoad,
+
+ // Used when performing a PC-relative branch where the
+ eContextRelativeBranchImmediate,
+
+ // Used when performing an absolute branch where the
+ eContextAbsoluteBranchRegister,
+
+ // Used when performing a supervisor call to an operating system to
+ // provide a service:
+ 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
+ eContextWriteRegisterRandomBits,
+
+ // Used when random bits are written to memory
+ eContextWriteMemoryRandomBits,
+
+ eContextArithmetic,
+
+ eContextAdvancePC,
+
+ eContextReturnFromException
+ };
+
+ enum InfoType {
+ eInfoTypeRegisterPlusOffset,
+ eInfoTypeRegisterPlusIndirectOffset,
+ eInfoTypeRegisterToRegisterPlusOffset,
+ eInfoTypeRegisterToRegisterPlusIndirectOffset,
+ eInfoTypeRegisterRegisterOperands,
+ eInfoTypeOffset,
+ eInfoTypeRegister,
+ eInfoTypeImmediate,
+ eInfoTypeImmediateSigned,
+ eInfoTypeAddress,
+ eInfoTypeISAAndImmediate,
+ eInfoTypeISAAndImmediateSigned,
+ eInfoTypeISA,
+ eInfoTypeNoArgs
+ } InfoType;
+
+ struct Context
+ {
+ ContextType type;
+ enum InfoType info_type;
+ union
+ {
+ struct RegisterPlusOffset
+ {
+ RegisterInfo reg; // base register
+ int64_t signed_offset; // signed offset added to base register
+ } RegisterPlusOffset;
+
+ struct RegisterPlusIndirectOffset
+ {
+ RegisterInfo base_reg; // base register number
+ RegisterInfo offset_reg; // offset register kind
+ } RegisterPlusIndirectOffset;
+
+ struct RegisterToRegisterPlusOffset
+ {
+ RegisterInfo data_reg; // source/target register for data
+ RegisterInfo base_reg; // base register for address calculation
+ int64_t offset; // offset for address calculation
+ } RegisterToRegisterPlusOffset;
+
+ struct RegisterToRegisterPlusIndirectOffset
+ {
+ RegisterInfo base_reg; // base register for address calculation
+ RegisterInfo offset_reg; // offset register for address calculation
+ RegisterInfo data_reg; // source/target register for data
+ } RegisterToRegisterPlusIndirectOffset;
+
+ struct RegisterRegisterOperands
+ {
+ RegisterInfo operand1; // register containing first operand for binary op
+ RegisterInfo operand2; // register containing second operand for binary op
+ } RegisterRegisterOperands;
+
+ int64_t signed_offset; // signed offset by which to adjust self (for registers only)
+
+ RegisterInfo reg; // plain register
+
+ uint64_t unsigned_immediate;// unsigned immediate value
+ int64_t signed_immediate; // signed immediate value
+
+ lldb::addr_t address; // direct address
+
+ struct ISAAndImmediate
+ {
+ uint32_t isa;
+ uint32_t unsigned_data32; // immdiate data
+ } ISAAndImmediate;
+
+ struct ISAAndImmediateSigned
+ {
+ uint32_t isa;
+ int32_t signed_data32; // signed immdiate data
+ } ISAAndImmediateSigned;
+
+ uint32_t isa;
+
+ } info;
+
+ Context () :
+ type (eContextInvalid),
+ info_type (eInfoTypeNoArgs)
+ {
+ }
+
+ void
+ SetRegisterPlusOffset (RegisterInfo base_reg,
+ int64_t signed_offset)
+ {
+ info_type = eInfoTypeRegisterPlusOffset;
+ info.RegisterPlusOffset.reg = base_reg;
+ info.RegisterPlusOffset.signed_offset = signed_offset;
+ }
+
+ void
+ SetRegisterPlusIndirectOffset (RegisterInfo base_reg,
+ RegisterInfo offset_reg)
+ {
+ info_type = eInfoTypeRegisterPlusIndirectOffset;
+ info.RegisterPlusIndirectOffset.base_reg = base_reg;
+ info.RegisterPlusIndirectOffset.offset_reg = offset_reg;
+ }
+
+ void
+ SetRegisterToRegisterPlusOffset (RegisterInfo data_reg,
+ RegisterInfo base_reg,
+ int64_t offset)
+ {
+ info_type = eInfoTypeRegisterToRegisterPlusOffset;
+ info.RegisterToRegisterPlusOffset.data_reg = data_reg;
+ info.RegisterToRegisterPlusOffset.base_reg = base_reg;
+ info.RegisterToRegisterPlusOffset.offset = offset;
+ }
+
+ void
+ SetRegisterToRegisterPlusIndirectOffset (RegisterInfo base_reg,
+ RegisterInfo offset_reg,
+ RegisterInfo data_reg)
+ {
+ info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset;
+ info.RegisterToRegisterPlusIndirectOffset.base_reg = base_reg;
+ info.RegisterToRegisterPlusIndirectOffset.offset_reg = offset_reg;
+ info.RegisterToRegisterPlusIndirectOffset.data_reg = data_reg;
+ }
+
+ void
+ SetRegisterRegisterOperands (RegisterInfo op1_reg,
+ RegisterInfo op2_reg)
+ {
+ info_type = eInfoTypeRegisterRegisterOperands;
+ info.RegisterRegisterOperands.operand1 = op1_reg;
+ info.RegisterRegisterOperands.operand2 = op2_reg;
+ }
+
+ void
+ SetOffset (int64_t signed_offset)
+ {
+ info_type = eInfoTypeOffset;
+ info.signed_offset = signed_offset;
+ }
+
+ void
+ SetRegister (RegisterInfo reg)
+ {
+ info_type = eInfoTypeRegister;
+ info.reg = reg;
+ }
+
+ void
+ SetImmediate (uint64_t immediate)
+ {
+ info_type = eInfoTypeImmediate;
+ info.unsigned_immediate = immediate;
+ }
+
+ void
+ SetImmediateSigned (int64_t signed_immediate)
+ {
+ info_type = eInfoTypeImmediateSigned;
+ info.signed_immediate = signed_immediate;
+ }
+
+ void
+ SetAddress (lldb::addr_t address)
+ {
+ info_type = eInfoTypeAddress;
+ info.address = address;
+ }
+ void
+ SetISAAndImmediate (uint32_t isa, uint32_t data)
+ {
+ info_type = eInfoTypeISAAndImmediate;
+ info.ISAAndImmediate.isa = isa;
+ info.ISAAndImmediate.unsigned_data32 = data;
+ }
+
+ void
+ SetISAAndImmediateSigned (uint32_t isa, int32_t data)
+ {
+ info_type = eInfoTypeISAAndImmediateSigned;
+ info.ISAAndImmediateSigned.isa = isa;
+ info.ISAAndImmediateSigned.signed_data32 = data;
+ }
+
+ void
+ SetISA (uint32_t isa)
+ {
+ info_type = eInfoTypeISA;
+ info.isa = isa;
+ }
+
+ void
+ SetNoArgs ()
+ {
+ info_type = eInfoTypeNoArgs;
+ }
+
+ void
+ Dump (Stream &s,
+ EmulateInstruction *instruction) const;
+
+ };
+
+ typedef size_t (*ReadMemoryCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ typedef size_t (*WriteMemoryCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ typedef bool (*ReadRegisterCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+ typedef bool (*WriteRegisterCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ EmulateInstruction (const ArchSpec &arch);
+
+ virtual ~EmulateInstruction()
+ {
+ }
+ //----------------------------------------------------------------------
+ // Mandatory overrides
+ //----------------------------------------------------------------------
+ virtual bool
+ SupportsEmulatingIntructionsOfType (InstructionType inst_type) = 0;
+
+ virtual bool
+ SetTargetTriple (const ArchSpec &arch) = 0;
+
+ virtual bool
+ ReadInstruction () = 0;
+
+ virtual bool
+ EvaluateInstruction (uint32_t evaluate_options) = 0;
+
+ virtual bool
+ TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) = 0;
+
+ virtual bool
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info) = 0;
+
+ //----------------------------------------------------------------------
+ // Optional overrides
+ //----------------------------------------------------------------------
+ virtual bool
+ SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target);
+
+ virtual bool
+ CreateFunctionEntryUnwind (UnwindPlan &unwind_plan);
+
+ static const char *
+ TranslateRegister (uint32_t reg_kind, uint32_t reg_num, std::string &reg_name);
+
+ //----------------------------------------------------------------------
+ // RegisterInfo variants
+ //----------------------------------------------------------------------
+ bool
+ ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue& reg_value);
+
+ uint64_t
+ ReadRegisterUnsigned (const RegisterInfo *reg_info,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteRegister (const Context &context,
+ const RegisterInfo *ref_info,
+ const RegisterValue& reg_value);
+
+ bool
+ WriteRegisterUnsigned (const Context &context,
+ const RegisterInfo *reg_info,
+ uint64_t reg_value);
+
+ //----------------------------------------------------------------------
+ // Register kind and number variants
+ //----------------------------------------------------------------------
+ bool
+ ReadRegister (uint32_t reg_kind,
+ uint32_t reg_num,
+ RegisterValue& reg_value);
+
+ bool
+ WriteRegister (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ const RegisterValue& reg_value);
+
+ uint64_t
+ ReadRegisterUnsigned (uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteRegisterUnsigned (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t reg_value);
+
+
+ size_t
+ ReadMemory (const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len);
+
+ uint64_t
+ ReadMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ size_t byte_size,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteMemory (const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len);
+
+ bool
+ WriteMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ uint64_t uval,
+ size_t uval_byte_size);
+
+ uint32_t
+ GetAddressByteSize () const
+ {
+ return m_arch.GetAddressByteSize();
+ }
+
+ lldb::ByteOrder
+ GetByteOrder () const
+ {
+ return m_arch.GetByteOrder();
+ }
+
+ const Opcode &
+ GetOpcode () const
+ {
+ return m_opcode;
+ }
+
+ lldb::addr_t
+ GetAddress () const
+ {
+ return m_addr;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+
+ static size_t
+ ReadMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+
+ static bool
+ WriteRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ static size_t
+ ReadMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+
+ static bool
+ WriteRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ void
+ SetBaton (void *baton);
+
+ void
+ SetCallbacks (ReadMemoryCallback read_mem_callback,
+ WriteMemoryCallback write_mem_callback,
+ ReadRegisterCallback read_reg_callback,
+ WriteRegisterCallback write_reg_callback);
+
+ void
+ SetReadMemCallback (ReadMemoryCallback read_mem_callback);
+
+ void
+ SetWriteMemCallback (WriteMemoryCallback write_mem_callback);
+
+ void
+ SetReadRegCallback (ReadRegisterCallback read_reg_callback);
+
+ void
+ SetWriteRegCallback (WriteRegisterCallback write_reg_callback);
+
+ static bool
+ GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
+ uint32_t &reg_kind,
+ uint32_t &reg_num);
+
+ static uint32_t
+ GetInternalRegisterNumber (RegisterContext *reg_ctx,
+ const RegisterInfo &reg_info);
+
+protected:
+ ArchSpec m_arch;
+ void * m_baton;
+ ReadMemoryCallback m_read_mem_callback;
+ WriteMemoryCallback m_write_mem_callback;
+ ReadRegisterCallback m_read_reg_callback;
+ WriteRegisterCallback m_write_reg_callback;
+ lldb::addr_t m_addr;
+ Opcode m_opcode;
+
+
+private:
+ //------------------------------------------------------------------
+ // For EmulateInstruction only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (EmulateInstruction);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_EmulateInstruction_h_
OpenPOWER on IntegriCloud