diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2013-08-23 17:46:38 +0000 |
| commit | f034231a6a1fd5d6395206c1651de8cd9402cca3 (patch) | |
| tree | f561dabc721ad515599172c16da3a4400b7f4aec /source/Core/EmulateInstruction.cpp | |
Notes
Diffstat (limited to 'source/Core/EmulateInstruction.cpp')
| -rw-r--r-- | source/Core/EmulateInstruction.cpp | 670 |
1 files changed, 670 insertions, 0 deletions
diff --git a/source/Core/EmulateInstruction.cpp b/source/Core/EmulateInstruction.cpp new file mode 100644 index 000000000000..bf6c6d88b563 --- /dev/null +++ b/source/Core/EmulateInstruction.cpp @@ -0,0 +1,670 @@ +//===-- 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 (uint32_t 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 (uint32_t 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, + uint32_t 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, + uint32_t 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); + uint32_t reg_kind, 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, + uint32_t ®_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) +{ + uint32_t reg_kind, 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; +} + + |
