diff options
Diffstat (limited to 'include/lldb/Core/EmulateInstruction.h')
-rw-r--r-- | include/lldb/Core/EmulateInstruction.h | 641 |
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 ®_value); + + typedef bool (*WriteRegisterCallback) (EmulateInstruction *instruction, + void *baton, + const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_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 ®_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 ®_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 ®_value); + + + static bool + WriteRegisterFrame (EmulateInstruction *instruction, + void *baton, + const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_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 ®_value); + + + static bool + WriteRegisterDefault (EmulateInstruction *instruction, + void *baton, + const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_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 ®_kind, + uint32_t ®_num); + + static uint32_t + GetInternalRegisterNumber (RegisterContext *reg_ctx, + const RegisterInfo ®_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_ |