//===-- EmulateInstruction.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Address.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "Plugins/Instruction/ARM/EmulateInstructionARM.h" using namespace lldb; using namespace lldb_private; EmulateInstruction* EmulateInstruction::FindPlugin (const ArchSpec &arch, InstructionType supported_inst_type, const char *plugin_name) { EmulateInstructionCreateInstance create_callback = NULL; if (plugin_name) { create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (plugin_name); if (create_callback) { EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type); if (emulate_insn_ptr) return emulate_insn_ptr; } } else { for (uint32_t idx = 0; (create_callback = PluginManager::GetEmulateInstructionCreateCallbackAtIndex(idx)) != NULL; ++idx) { EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type); if (emulate_insn_ptr) return emulate_insn_ptr; } } return NULL; } EmulateInstruction::EmulateInstruction (const ArchSpec &arch) : m_arch (arch), m_baton (NULL), m_read_mem_callback (&ReadMemoryDefault), m_write_mem_callback (&WriteMemoryDefault), m_read_reg_callback (&ReadRegisterDefault), m_write_reg_callback (&WriteRegisterDefault), m_opcode_pc (LLDB_INVALID_ADDRESS) { ::memset (&m_opcode, 0, sizeof (m_opcode)); } uint64_t EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind, uint32_t reg_num, uint64_t fail_value, bool *success_ptr) { uint64_t uval64 = 0; bool success = m_read_reg_callback (this, m_baton, reg_kind, reg_num, uval64); if (success_ptr) *success_ptr = success; if (!success) uval64 = fail_value; return uval64; } bool EmulateInstruction::WriteRegisterUnsigned (const Context &context, uint32_t reg_kind, uint32_t reg_num, uint64_t reg_value) { return m_write_reg_callback (this, m_baton, context, reg_kind, reg_num, reg_value); } uint64_t EmulateInstruction::ReadMemoryUnsigned (const Context &context, lldb::addr_t addr, size_t byte_size, uint64_t fail_value, bool *success_ptr) { uint64_t uval64 = 0; bool success = false; if (byte_size <= 8) { uint8_t buf[sizeof(uint64_t)]; size_t bytes_read = m_read_mem_callback (this, m_baton, context, addr, buf, byte_size); if (bytes_read == byte_size) { uint32_t offset = 0; DataExtractor data (buf, byte_size, GetByteOrder(), GetAddressByteSize()); uval64 = data.GetMaxU64 (&offset, byte_size); success = true; } } if (success_ptr) *success_ptr = success; if (!success) uval64 = fail_value; return uval64; } bool EmulateInstruction::WriteMemoryUnsigned (const Context &context, lldb::addr_t addr, uint64_t uval, size_t uval_byte_size) { StreamString strm(Stream::eBinary, GetAddressByteSize(), GetByteOrder()); strm.PutMaxHex64 (uval, uval_byte_size); size_t bytes_written = m_write_mem_callback (this, m_baton, context, addr, strm.GetData(), uval_byte_size); if (bytes_written == uval_byte_size) return true; return false; } void EmulateInstruction::SetBaton (void *baton) { m_baton = baton; } void EmulateInstruction::SetCallbacks (ReadMemory read_mem_callback, WriteMemory write_mem_callback, ReadRegister read_reg_callback, WriteRegister write_reg_callback) { m_read_mem_callback = read_mem_callback; m_write_mem_callback = write_mem_callback; m_read_reg_callback = read_reg_callback; m_write_reg_callback = write_reg_callback; } void EmulateInstruction::SetReadMemCallback (ReadMemory read_mem_callback) { m_read_mem_callback = read_mem_callback; } void EmulateInstruction::SetWriteMemCallback (WriteMemory write_mem_callback) { m_write_mem_callback = write_mem_callback; } void EmulateInstruction::SetReadRegCallback (ReadRegister read_reg_callback) { m_read_reg_callback = read_reg_callback; } void EmulateInstruction::SetWriteRegCallback (WriteRegister write_reg_callback) { m_write_reg_callback = write_reg_callback; } // // Read & Write Memory and Registers callback functions. // size_t EmulateInstruction::ReadMemoryFrame (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, void *dst, size_t length) { if (!baton) return 0; StackFrame *frame = (StackFrame *) baton; DataBufferSP data_sp (new DataBufferHeap (length, '\0')); Error error; size_t bytes_read = frame->GetThread().GetProcess().ReadMemory (addr, data_sp->GetBytes(), data_sp->GetByteSize(), error); if (bytes_read > 0) ((DataBufferHeap *) data_sp.get())->CopyData (dst, length); return bytes_read; } size_t EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, const void *dst, size_t length) { if (!baton) return 0; StackFrame *frame = (StackFrame *) baton; lldb::DataBufferSP data_sp (new DataBufferHeap (dst, length)); if (data_sp) { length = data_sp->GetByteSize(); if (length > 0) { Error error; size_t bytes_written = frame->GetThread().GetProcess().WriteMemory (addr, data_sp->GetBytes(), length, error); return bytes_written; } } return 0; } bool EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction, void *baton, uint32_t reg_kind, uint32_t reg_num, uint64_t ®_value) { if (!baton) return false; StackFrame *frame = (StackFrame *) baton; RegisterContext *reg_context = frame->GetRegisterContext().get(); Scalar value; uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num); if (internal_reg_num == LLDB_INVALID_REGNUM) return false; if (reg_context->ReadRegisterValue (internal_reg_num, value)) { reg_value = value.GetRawBits64 (0); return true; } return false; } bool EmulateInstruction::WriteRegisterFrame (EmulateInstruction *instruction, void *baton, const Context &context, uint32_t reg_kind, uint32_t reg_num, uint64_t reg_value) { if (!baton) return false; StackFrame *frame = (StackFrame *) baton; RegisterContext *reg_context = frame->GetRegisterContext().get(); Scalar value (reg_value); uint32_t internal_reg_num = reg_context->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num); if (internal_reg_num != LLDB_INVALID_REGNUM) return reg_context->WriteRegisterValue (internal_reg_num, value); else return false; } size_t EmulateInstruction::ReadMemoryDefault (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, void *dst, size_t length) { PrintContext ("Read from memory", context); fprintf (stdout, " Read from Memory (address = %p, length = %d)\n",(void *) addr, (uint32_t) length); *((uint64_t *) dst) = 0xdeadbeef; return length; } size_t EmulateInstruction::WriteMemoryDefault (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, const void *dst, size_t length) { PrintContext ("Write to memory", context); fprintf (stdout, " Write to Memory (address = %p, length = %d)\n", (void *) addr, (uint32_t) length); return length; } bool EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction, void *baton, uint32_t reg_kind, uint32_t reg_num, uint64_t ®_value) { std::string reg_name; TranslateRegister (reg_kind, reg_num, reg_name); fprintf (stdout, " Read Register (%s)\n", reg_name.c_str()); reg_value = 24; return true; } bool EmulateInstruction::WriteRegisterDefault (EmulateInstruction *instruction, void *baton, const Context &context, uint32_t reg_kind, uint32_t reg_num, uint64_t reg_value) { PrintContext ("Write to register", context); std::string reg_name; TranslateRegister (reg_kind, reg_num, reg_name); fprintf (stdout, " Write to Register (%s), value = 0x%llx\n", reg_name.c_str(), reg_value); return true; } void EmulateInstruction::PrintContext (const char *context_type, const Context &context) { switch (context.type) { case eContextReadOpcode: fprintf (stdout, " %s context: Reading an Opcode\n", context_type); break; case eContextImmediate: fprintf (stdout, " %s context: Immediate\n", context_type); break; case eContextPushRegisterOnStack: fprintf (stdout, " %s context: Pushing a register onto the stack.\n", context_type); break; case eContextPopRegisterOffStack: fprintf (stdout, " %s context: Popping a register off the stack.\n", context_type); break; case eContextAdjustStackPointer: fprintf (stdout, " %s context: Adjusting the stack pointer.\n", context_type); break; case eContextAdjustBaseRegister: fprintf (stdout, " %s context: Adjusting (writing value back to) a base register.\n", context_type); break; case eContextRegisterPlusOffset: fprintf (stdout, " %s context: Register plus offset\n", context_type); break; case eContextRegisterStore: fprintf (stdout, " %s context: Storing a register.\n", context_type); break; case eContextRegisterLoad: fprintf (stdout, " %s context: Loading a register.\n", context_type); break; case eContextRelativeBranchImmediate: fprintf (stdout, " %s context: Relative branch immediate\n", context_type); break; case eContextAbsoluteBranchRegister: fprintf (stdout, " %s context: Absolute branch register\n", context_type); break; case eContextSupervisorCall: fprintf (stdout, " %s context: Performing a supervisor call.\n", context_type); break; case eContextTableBranchReadMemory: fprintf (stdout, " %s context: Table branch read memory\n", context_type); break; case eContextWriteRegisterRandomBits: fprintf (stdout, " %s context: Write random bits to a register\n", context_type); break; case eContextWriteMemoryRandomBits: fprintf (stdout, " %s context: Write random bits to a memory address\n", context_type); break; case eContextMultiplication: fprintf (stdout, " %s context: Performing a multiplication\n", context_type); break; case eContextAddition: fprintf (stdout, " %s context: Performing an addition\n", context_type); break; case eContextReturnFromException: fprintf (stdout, " %s context: Returning from an exception\n", context_type); break; default: fprintf (stdout, " %s context: Unrecognized context.\n", context_type); break; } switch (context.info_type) { case eInfoTypeRegisterPlusOffset: { std::string reg_name; TranslateRegister (context.info.RegisterPlusOffset.reg.kind, context.info.RegisterPlusOffset.reg.num, reg_name); fprintf (stdout, " Info type: Register plus offset (%s +/- %lld)\n", reg_name.c_str(), context.info.RegisterPlusOffset.signed_offset); } break; case eInfoTypeRegisterPlusIndirectOffset: { std::string base_reg_name; std::string offset_reg_name; TranslateRegister (context.info.RegisterPlusIndirectOffset.base_reg.kind, context.info.RegisterPlusIndirectOffset.base_reg.num, base_reg_name); TranslateRegister (context.info.RegisterPlusIndirectOffset.offset_reg.kind, context.info.RegisterPlusIndirectOffset.offset_reg.num, offset_reg_name); fprintf (stdout, " Info type: Register plus indirect offset (%s +/- %s)\n", base_reg_name.c_str(), offset_reg_name.c_str()); } break; case eInfoTypeRegisterToRegisterPlusOffset: { std::string base_reg_name; std::string data_reg_name; TranslateRegister (context.info.RegisterToRegisterPlusOffset.base_reg.kind, context.info.RegisterToRegisterPlusOffset.base_reg.num, base_reg_name); TranslateRegister (context.info.RegisterToRegisterPlusOffset.data_reg.kind, context.info.RegisterToRegisterPlusOffset.data_reg.num, data_reg_name); fprintf (stdout, " Info type: Register plus offset (%s +/- %lld) and data register (%s)\n", base_reg_name.c_str(), context.info.RegisterToRegisterPlusOffset.offset, data_reg_name.c_str()); } break; case eInfoTypeRegisterToRegisterPlusIndirectOffset: { std::string base_reg_name; std::string offset_reg_name; std::string data_reg_name; TranslateRegister (context.info.RegisterToRegisterPlusIndirectOffset.base_reg.kind, context.info.RegisterToRegisterPlusIndirectOffset.base_reg.num, base_reg_name); TranslateRegister (context.info.RegisterToRegisterPlusIndirectOffset.offset_reg.kind, context.info.RegisterToRegisterPlusIndirectOffset.offset_reg.num, offset_reg_name); TranslateRegister (context.info.RegisterToRegisterPlusIndirectOffset.data_reg.kind, context.info.RegisterToRegisterPlusIndirectOffset.data_reg.num, data_reg_name); fprintf (stdout, " Info type: Register plus indirect offset (%s +/- %s) and data register (%s)\n", base_reg_name.c_str(), offset_reg_name.c_str(), data_reg_name.c_str()); } break; case eInfoTypeRegisterRegisterOperands: { std::string op1_reg_name; std::string op2_reg_name; TranslateRegister (context.info.RegisterRegisterOperands.operand1.kind, context.info.RegisterRegisterOperands.operand1.num, op1_reg_name); TranslateRegister (context.info.RegisterRegisterOperands.operand2.kind, context.info.RegisterRegisterOperands.operand2.num, op2_reg_name); fprintf (stdout, " Info type: Register operands for binary op (%s, %s)\n", op1_reg_name.c_str(), op2_reg_name.c_str()); } break; case eInfoTypeOffset: fprintf (stdout, " Info type: signed offset (%lld)\n", context.info.signed_offset); break; case eInfoTypeRegister: { std::string reg_name; TranslateRegister (context.info.reg.kind, context.info.reg.num, reg_name); fprintf (stdout, " Info type: Register (%s)\n", reg_name.c_str()); } break; case eInfoTypeImmediate: fprintf (stdout, " Info type: Immediate (%lld)\n", context.info.immediate); break; case eInfoTypeImmediateSigned: fprintf (stdout, " Info type: Signed immediate (%lld)\n", context.info.signed_immediate); break; case eInfoTypeAddress: fprintf (stdout, " Info type: Address (%p)\n", (void *) context.info.address); break; case eInfoTypeModeAndImmediate: { std::string mode_name; if (context.info.ModeAndImmediate.mode == EmulateInstructionARM::eModeARM) mode_name = "ARM"; else if (context.info.ModeAndImmediate.mode == EmulateInstructionARM::eModeThumb) mode_name = "Thumb"; else mode_name = "Unknown mode"; fprintf (stdout, " Info type: Mode (%s) and immediate (%d)\n", mode_name.c_str(), context.info.ModeAndImmediate.data_value); } break; case eInfoTypeModeAndImmediateSigned: { std::string mode_name; if (context.info.ModeAndImmediateSigned.mode == EmulateInstructionARM::eModeARM) mode_name = "ARM"; else if (context.info.ModeAndImmediateSigned.mode == EmulateInstructionARM::eModeThumb) mode_name = "Thumb"; else mode_name = "Unknown mode"; fprintf (stdout, " Info type: Mode (%s) and signed immediate (%d)\n", mode_name.c_str(), context.info.ModeAndImmediateSigned.signed_data_value); } break; case eInfoTypeMode: { std::string mode_name; if (context.info.mode == EmulateInstructionARM::eModeARM) mode_name = "ARM"; else if (context.info.mode == EmulateInstructionARM::eModeThumb) mode_name = "Thumb"; else mode_name = "Unknown mode"; fprintf (stdout, " Info type: Mode (%s)\n", mode_name.c_str()); } break; case eInfoTypeNoArgs: fprintf (stdout, " Info type: no arguments\n"); break; default: break; } } bool EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_addr, Target *target) { m_opcode = opcode; m_opcode_pc = LLDB_INVALID_ADDRESS; if (inst_addr.IsValid()) { if (target) m_opcode_pc = inst_addr.GetLoadAddress (target); if (m_opcode_pc == LLDB_INVALID_ADDRESS) m_opcode_pc = inst_addr.GetFileAddress (); } return true; } const char * EmulateInstruction::TranslateRegister (uint32_t kind, uint32_t num, std::string &name) { if (kind == eRegisterKindGeneric) { switch (num) { case LLDB_REGNUM_GENERIC_PC: name = "pc"; break; case LLDB_REGNUM_GENERIC_SP: name = "sp"; break; case LLDB_REGNUM_GENERIC_FP: name = "fp"; break; case LLDB_REGNUM_GENERIC_RA: name = "ra"; break; case LLDB_REGNUM_GENERIC_FLAGS: name = "flags"; break; default: name.clear(); break; } if (!name.empty()) return name.c_str(); } const char *kind_cstr = NULL; switch (kind) { case eRegisterKindGCC: // the register numbers seen in eh_frame kind_cstr = "gcc"; break; case eRegisterKindDWARF: // the register numbers seen DWARF kind_cstr = "dwarf"; break; case eRegisterKindGeneric: // insn ptr reg, stack ptr reg, etc not specific to any particular target kind_cstr = "generic"; break; case eRegisterKindGDB: // the register numbers gdb uses (matches stabs numbers?) kind_cstr = "gdb"; break; case eRegisterKindLLDB: // lldb's internal register numbers kind_cstr = "lldb"; break; } StreamString sstr; sstr.Printf ("%s(%u)", kind_cstr, num); name.swap (sstr.GetString()); return name.c_str(); }