//===-- 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/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.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) { ConstString const_plugin_name (plugin_name); create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const_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_addr (LLDB_INVALID_ADDRESS) { ::memset (&m_opcode, 0, sizeof (m_opcode)); } bool EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& reg_value) { if (m_read_reg_callback) return m_read_reg_callback (this, m_baton, reg_info, reg_value); return false; } bool EmulateInstruction::ReadRegister (lldb::RegisterKind reg_kind, uint32_t reg_num, RegisterValue& reg_value) { RegisterInfo reg_info; if (GetRegisterInfo(reg_kind, reg_num, reg_info)) return ReadRegister (®_info, reg_value); return false; } uint64_t EmulateInstruction::ReadRegisterUnsigned (lldb::RegisterKind reg_kind, uint32_t reg_num, uint64_t fail_value, bool *success_ptr) { RegisterValue reg_value; if (ReadRegister (reg_kind, reg_num, reg_value)) return reg_value.GetAsUInt64(fail_value, success_ptr); if (success_ptr) *success_ptr = false; return fail_value; } uint64_t EmulateInstruction::ReadRegisterUnsigned (const RegisterInfo *reg_info, uint64_t fail_value, bool *success_ptr) { RegisterValue reg_value; if (ReadRegister (reg_info, reg_value)) return reg_value.GetAsUInt64(fail_value, success_ptr); if (success_ptr) *success_ptr = false; return fail_value; } bool EmulateInstruction::WriteRegister (const Context &context, const RegisterInfo *reg_info, const RegisterValue& reg_value) { if (m_write_reg_callback) return m_write_reg_callback (this, m_baton, context, reg_info, reg_value); return false; } bool EmulateInstruction::WriteRegister (const Context &context, lldb::RegisterKind reg_kind, uint32_t reg_num, const RegisterValue& reg_value) { RegisterInfo reg_info; if (GetRegisterInfo(reg_kind, reg_num, reg_info)) return WriteRegister (context, ®_info, reg_value); return false; } bool EmulateInstruction::WriteRegisterUnsigned (const Context &context, lldb::RegisterKind reg_kind, uint32_t reg_num, uint64_t uint_value) { RegisterInfo reg_info; if (GetRegisterInfo(reg_kind, reg_num, reg_info)) { RegisterValue reg_value; if (reg_value.SetUInt(uint_value, reg_info.byte_size)) return WriteRegister (context, ®_info, reg_value); } return false; } bool EmulateInstruction::WriteRegisterUnsigned (const Context &context, const RegisterInfo *reg_info, uint64_t uint_value) { if (reg_info) { RegisterValue reg_value; if (reg_value.SetUInt(uint_value, reg_info->byte_size)) return WriteRegister (context, reg_info, reg_value); } return false; } size_t EmulateInstruction::ReadMemory (const Context &context, lldb::addr_t addr, void *dst, size_t dst_len) { if (m_read_mem_callback) return m_read_mem_callback (this, m_baton, context, addr, dst, dst_len) == dst_len; return false; } 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) { lldb::offset_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; } bool EmulateInstruction::WriteMemory (const Context &context, lldb::addr_t addr, const void *src, size_t src_len) { if (m_write_mem_callback) return m_write_mem_callback (this, m_baton, context, addr, src, src_len) == src_len; return false; } void EmulateInstruction::SetBaton (void *baton) { m_baton = baton; } void EmulateInstruction::SetCallbacks (ReadMemoryCallback read_mem_callback, WriteMemoryCallback write_mem_callback, ReadRegisterCallback read_reg_callback, WriteRegisterCallback 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 (ReadMemoryCallback read_mem_callback) { m_read_mem_callback = read_mem_callback; } void EmulateInstruction::SetWriteMemCallback (WriteMemoryCallback write_mem_callback) { m_write_mem_callback = write_mem_callback; } void EmulateInstruction::SetReadRegCallback (ReadRegisterCallback read_reg_callback) { m_read_reg_callback = read_reg_callback; } void EmulateInstruction::SetWriteRegCallback (WriteRegisterCallback 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 dst_len) { if (!baton || dst == NULL || dst_len == 0) return 0; StackFrame *frame = (StackFrame *) baton; ProcessSP process_sp (frame->CalculateProcess()); if (process_sp) { Error error; return process_sp->ReadMemory (addr, dst, dst_len, error); } return 0; } size_t EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, const void *src, size_t src_len) { if (!baton || src == NULL || src_len == 0) return 0; StackFrame *frame = (StackFrame *) baton; ProcessSP process_sp (frame->CalculateProcess()); if (process_sp) { Error error; return process_sp->WriteMemory (addr, src, src_len, error); } return 0; } bool EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction, void *baton, const RegisterInfo *reg_info, RegisterValue ®_value) { if (!baton) return false; StackFrame *frame = (StackFrame *) baton; return frame->GetRegisterContext()->ReadRegister (reg_info, reg_value); } bool EmulateInstruction::WriteRegisterFrame (EmulateInstruction *instruction, void *baton, const Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { if (!baton) return false; StackFrame *frame = (StackFrame *) baton; return frame->GetRegisterContext()->WriteRegister (reg_info, reg_value); } size_t EmulateInstruction::ReadMemoryDefault (EmulateInstruction *instruction, void *baton, const Context &context, lldb::addr_t addr, void *dst, size_t length) { StreamFile strm (stdout, false); strm.Printf (" Read from Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length); context.Dump (strm, instruction); strm.EOL(); *((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) { StreamFile strm (stdout, false); strm.Printf (" Write to Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length); context.Dump (strm, instruction); strm.EOL(); return length; } bool EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction, void *baton, const RegisterInfo *reg_info, RegisterValue ®_value) { StreamFile strm (stdout, false); strm.Printf (" Read Register (%s)\n", reg_info->name); lldb::RegisterKind reg_kind; uint32_t reg_num; if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num)) reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num); else reg_value.SetUInt64(0); return true; } bool EmulateInstruction::WriteRegisterDefault (EmulateInstruction *instruction, void *baton, const Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { StreamFile strm (stdout, false); strm.Printf (" Write to Register (name = %s, value = " , reg_info->name); reg_value.Dump(&strm, reg_info, false, false, eFormatDefault); strm.PutCString (", context = "); context.Dump (strm, instruction); strm.EOL(); return true; } void EmulateInstruction::Context::Dump (Stream &strm, EmulateInstruction *instruction) const { switch (type) { case eContextReadOpcode: strm.PutCString ("reading opcode"); break; case eContextImmediate: strm.PutCString ("immediate"); break; case eContextPushRegisterOnStack: strm.PutCString ("push register"); break; case eContextPopRegisterOffStack: strm.PutCString ("pop register"); break; case eContextAdjustStackPointer: strm.PutCString ("adjust sp"); break; case eContextSetFramePointer: strm.PutCString ("set frame pointer"); break; case eContextAdjustBaseRegister: strm.PutCString ("adjusting (writing value back to) a base register"); break; case eContextRegisterPlusOffset: strm.PutCString ("register + offset"); break; case eContextRegisterStore: strm.PutCString ("store register"); break; case eContextRegisterLoad: strm.PutCString ("load register"); break; case eContextRelativeBranchImmediate: strm.PutCString ("relative branch immediate"); break; case eContextAbsoluteBranchRegister: strm.PutCString ("absolute branch register"); break; case eContextSupervisorCall: strm.PutCString ("supervisor call"); break; case eContextTableBranchReadMemory: strm.PutCString ("table branch read memory"); break; case eContextWriteRegisterRandomBits: strm.PutCString ("write random bits to a register"); break; case eContextWriteMemoryRandomBits: strm.PutCString ("write random bits to a memory address"); break; case eContextArithmetic: strm.PutCString ("arithmetic"); break; case eContextReturnFromException: strm.PutCString ("return from exception"); break; default: strm.PutCString ("unrecognized context."); break; } switch (info_type) { case eInfoTypeRegisterPlusOffset: { strm.Printf (" (reg_plus_offset = %s%+" PRId64 ")", info.RegisterPlusOffset.reg.name, info.RegisterPlusOffset.signed_offset); } break; case eInfoTypeRegisterPlusIndirectOffset: { strm.Printf (" (reg_plus_reg = %s + %s)", info.RegisterPlusIndirectOffset.base_reg.name, info.RegisterPlusIndirectOffset.offset_reg.name); } break; case eInfoTypeRegisterToRegisterPlusOffset: { strm.Printf (" (base_and_imm_offset = %s%+" PRId64 ", data_reg = %s)", info.RegisterToRegisterPlusOffset.base_reg.name, info.RegisterToRegisterPlusOffset.offset, info.RegisterToRegisterPlusOffset.data_reg.name); } break; case eInfoTypeRegisterToRegisterPlusIndirectOffset: { strm.Printf (" (base_and_reg_offset = %s + %s, data_reg = %s)", info.RegisterToRegisterPlusIndirectOffset.base_reg.name, info.RegisterToRegisterPlusIndirectOffset.offset_reg.name, info.RegisterToRegisterPlusIndirectOffset.data_reg.name); } break; case eInfoTypeRegisterRegisterOperands: { strm.Printf (" (register to register binary op: %s and %s)", info.RegisterRegisterOperands.operand1.name, info.RegisterRegisterOperands.operand2.name); } break; case eInfoTypeOffset: strm.Printf (" (signed_offset = %+" PRId64 ")", info.signed_offset); break; case eInfoTypeRegister: strm.Printf (" (reg = %s)", info.reg.name); break; case eInfoTypeImmediate: strm.Printf (" (unsigned_immediate = %" PRIu64 " (0x%16.16" PRIx64 "))", info.unsigned_immediate, info.unsigned_immediate); break; case eInfoTypeImmediateSigned: strm.Printf (" (signed_immediate = %+" PRId64 " (0x%16.16" PRIx64 "))", info.signed_immediate, info.signed_immediate); break; case eInfoTypeAddress: strm.Printf (" (address = 0x%" PRIx64 ")", info.address); break; case eInfoTypeISAAndImmediate: strm.Printf (" (isa = %u, unsigned_immediate = %u (0x%8.8x))", info.ISAAndImmediate.isa, info.ISAAndImmediate.unsigned_data32, info.ISAAndImmediate.unsigned_data32); break; case eInfoTypeISAAndImmediateSigned: strm.Printf (" (isa = %u, signed_immediate = %i (0x%8.8x))", info.ISAAndImmediateSigned.isa, info.ISAAndImmediateSigned.signed_data32, info.ISAAndImmediateSigned.signed_data32); break; case eInfoTypeISA: strm.Printf (" (isa = %u)", info.isa); break; case eInfoTypeNoArgs: break; } } bool EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_addr, Target *target) { m_opcode = opcode; m_addr = LLDB_INVALID_ADDRESS; if (inst_addr.IsValid()) { if (target) m_addr = inst_addr.GetLoadAddress (target); if (m_addr == LLDB_INVALID_ADDRESS) m_addr = inst_addr.GetFileAddress (); } return true; } bool EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info, lldb::RegisterKind ®_kind, uint32_t ®_num) { // Generic and DWARF should be the two most popular register kinds when // emulating instructions since they are the most platform agnostic... reg_num = reg_info->kinds[eRegisterKindGeneric]; if (reg_num != LLDB_INVALID_REGNUM) { reg_kind = eRegisterKindGeneric; return true; } reg_num = reg_info->kinds[eRegisterKindDWARF]; if (reg_num != LLDB_INVALID_REGNUM) { reg_kind = eRegisterKindDWARF; return true; } reg_num = reg_info->kinds[eRegisterKindLLDB]; if (reg_num != LLDB_INVALID_REGNUM) { reg_kind = eRegisterKindLLDB; return true; } reg_num = reg_info->kinds[eRegisterKindGCC]; if (reg_num != LLDB_INVALID_REGNUM) { reg_kind = eRegisterKindGCC; return true; } reg_num = reg_info->kinds[eRegisterKindGDB]; if (reg_num != LLDB_INVALID_REGNUM) { reg_kind = eRegisterKindGDB; return true; } return false; } uint32_t EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo ®_info) { lldb::RegisterKind reg_kind; uint32_t reg_num; if (reg_ctx && GetBestRegisterKindAndNumber (®_info, reg_kind, reg_num)) return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num); return LLDB_INVALID_REGNUM; } bool EmulateInstruction::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) { unwind_plan.Clear(); return false; }