mirror of
https://github.com/opnsense/src.git
synced 2026-03-03 13:51:30 -05:00
641 lines
22 KiB
C++
641 lines
22 KiB
C++
//===-- 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 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.
|
|
//----------------------------------------------------------------------
|
|
|
|
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
|
|
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 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_
|