//===-- 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 #include "lldb/Core/Address.h" // for Address #include "lldb/Core/Opcode.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN #include "lldb/lldb-enumerations.h" // for RegisterKind, ByteOrder #include "lldb/lldb-private-enumerations.h" // for InstructionType #include "lldb/lldb-private-types.h" // for RegisterInfo #include "lldb/lldb-types.h" // for addr_t #include // for size_t #include // for uint32_t, uint64_t, int64_t namespace lldb_private { class OptionValueDictionary; } namespace lldb_private { class RegisterContext; } namespace lldb_private { class RegisterValue; } namespace lldb_private { class Stream; } namespace lldb_private { class Target; } namespace lldb_private { class UnwindPlan; } namespace lldb_private { //---------------------------------------------------------------------- /// @class EmulateInstruction EmulateInstruction.h /// "lldb/Core/EmulateInstruction.h" /// 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 opcode, /// 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 instruction is just a bonus. //---------------------------------------------------------------------- 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 instruction 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, // Typically in an epilogue sequence. Copy the frame pointer back into the // stack pointer, use SP for CFA calculations again. eContextRestoreStackPointer, // 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; // immediate data } ISAAndImmediate; struct ISAAndImmediateSigned { uint32_t isa; int32_t signed_data32; // signed immediate 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); // Type to represent the condition of an instruction. The UINT32 value is // reserved for the unconditional case and all other value can be used in an // architecture dependent way. typedef uint32_t InstructionCondition; static const InstructionCondition UnconditionalCondition = UINT32_MAX; EmulateInstruction(const ArchSpec &arch); ~EmulateInstruction() override = default; //---------------------------------------------------------------------- // Mandatory overrides //---------------------------------------------------------------------- virtual bool SupportsEmulatingInstructionsOfType(InstructionType inst_type) = 0; virtual bool SetTargetTriple(const ArchSpec &arch) = 0; virtual bool ReadInstruction() = 0; virtual bool EvaluateInstruction(uint32_t evaluate_options) = 0; virtual InstructionCondition GetInstructionCondition() { return UnconditionalCondition; } virtual bool TestEmulation(Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) = 0; virtual bool GetRegisterInfo(lldb::RegisterKind 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(lldb::RegisterKind reg_kind, uint32_t reg_num, std::string ®_name); //---------------------------------------------------------------------- // RegisterInfo variants //---------------------------------------------------------------------- bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_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 ®_value); bool WriteRegisterUnsigned(const Context &context, const RegisterInfo *reg_info, uint64_t reg_value); //---------------------------------------------------------------------- // Register kind and number variants //---------------------------------------------------------------------- bool ReadRegister(lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterValue ®_value); bool WriteRegister(const Context &context, lldb::RegisterKind reg_kind, uint32_t reg_num, const RegisterValue ®_value); uint64_t ReadRegisterUnsigned(lldb::RegisterKind reg_kind, uint32_t reg_num, uint64_t fail_value, bool *success_ptr); bool WriteRegisterUnsigned(const Context &context, lldb::RegisterKind 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, lldb::RegisterKind ®_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_