miasm2.arch.mep.jit module
# Toshiba MeP-c4 - miasm jitter # Guillaume Valadon <guillaume@valadon.net> # Note: inspiration from msp430/jit.py from miasm2.jitter.jitload import Jitter from miasm2.core.locationdb import LocationDB from miasm2.core.utils import * from miasm2.jitter.codegen import CGen from miasm2.ir.translators.C import TranslatorC from miasm2.arch.mep.sem import ir_mepl, ir_mepb import logging log = logging.getLogger("jit_mep") hnd = logging.StreamHandler() hnd.setFormatter(logging.Formatter("[%(levelname)s]: %(message)s")) log.addHandler(hnd) log.setLevel(logging.CRITICAL) class mep_CGen(CGen): """ Translate a bloc containing MeP instructions to C Note: it is used to emulate the *REPEAT instructions """ def __init__(self, ir_arch): self.ir_arch = ir_arch self.PC = self.ir_arch.arch.regs.PC self.translator = TranslatorC(self.ir_arch.loc_db) self.init_arch_C() def gen_pre_code(self, attrib): """Generate C code inserted before the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_pre_code(attrib) # Set the PC register value explicitly out.append("mycpu->PC = 0x%X;" % attrib.instr.offset) out.append("mycpu->last_addr = mycpu->PC;"); return out def gen_post_code(self, attrib): """Generate C code inserted after the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_post_code(attrib) # Implement the *REPEAT instructions logics tmp = r""" /* *REPEAT instructions logic */ { uint32_t is_repeat_end = mycpu->is_repeat_end; mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1)); if (is_repeat_end && !mycpu->take_jmp && (mycpu->in_erepeat || mycpu->RPC)) { if (mycpu->RPC) mycpu->RPC --; //printf("Go repeat %X\n", mycpu->RPB); DST_value = mycpu->RPB; BlockDst->address = mycpu->RPB; return JIT_RET_NO_EXCEPTION; } } """ out += tmp.split('`\n') return out class jitter_mepl(Jitter): C_Gen = mep_CGen def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepl(sp), *args, **kwargs) self.vm.set_little_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC def push_uint16_t(self, v): regs = self.cpu.get_gpreg() regs["SP"] -= 2 self.cpu.set_gpreg(regs) self.vm.set_mem(regs["SP"], pck16(v)) def pop_uint16_t(self): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"], 2)) regs["SP"] += 2 self.cpu.set_gpreg(regs) return x def get_stack_arg(self, n): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"] + 2 * n, 2)) return x def init_run(self, *args, **kwargs): Jitter.init_run(self, *args, **kwargs) self.cpu.PC = self.pc class jitter_mepb(jitter_mepl): def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepb(sp), *args, **kwargs) self.vm.set_big_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
Module variables
var hnd
var log
var pck
Classes
class jitter_mepb
class jitter_mepb(jitter_mepl): def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepb(sp), *args, **kwargs) self.vm.set_big_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
Ancestors (in MRO)
- jitter_mepb
- jitter_mepl
- miasm2.jitter.jitload.Jitter
- __builtin__.object
Class variables
Static methods
def handle_lib(
jitter)
Inheritance:
jitter_mepl
.handle_lib
Resolve the name of the function which cause the handler call. Then call the corresponding handler from users callback.
@staticmethod def handle_lib(jitter): """Resolve the name of the function which cause the handler call. Then call the corresponding handler from users callback. """ fname = jitter.libs.fad2cname[jitter.pc] if fname in jitter.user_globals: func = jitter.user_globals[fname] else: log.debug('%r', fname) raise ValueError('unknown api', hex(jitter.pc), repr(fname)) ret = func(jitter) jitter.pc = getattr(jitter.cpu, jitter.ir_arch.pc.name) # Don't break on a None return if ret is None: return True else: return ret
Methods
def __init__(
self, *args, **kwargs)
Inheritance:
jitter_mepl
.__init__
def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepb(sp), *args, **kwargs) self.vm.set_big_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
def add_breakpoint(
self, addr, callback)
Inheritance:
jitter_mepl
.add_breakpoint
Add a callback associated with addr. @addr: breakpoint address @callback: function with definition (jitter instance)
def add_breakpoint(self, addr, callback): """Add a callback associated with addr. @addr: breakpoint address @callback: function with definition (jitter instance) """ self.breakpoints_handler.add_callback(addr, callback) self.jit.add_disassembly_splits(addr) # De-jit previously jitted blocks self.jit.updt_automod_code_range(self.vm, [(addr, addr)])
def add_exception_handler(
self, flag, callback)
Inheritance:
jitter_mepl
.add_exception_handler
Add a callback associated with an exception flag. @flag: bitflag @callback: function with definition (jitter instance)
def add_exception_handler(self, flag, callback): """Add a callback associated with an exception flag. @flag: bitflag @callback: function with definition (jitter instance) """ self.exceptions_handler.add_callback(flag, callback)
def add_lib_handler(
self, libs, user_globals=None)
Inheritance:
jitter_mepl
.add_lib_handler
Add a function to handle libs call with breakpoints @libs: libimp instance @user_globals: dictionary for defined user function
def add_lib_handler(self, libs, user_globals=None): """Add a function to handle libs call with breakpoints @libs: libimp instance @user_globals: dictionary for defined user function """ if user_globals is None: user_globals = {} self.libs = libs self.user_globals = user_globals for f_addr in libs.fad2cname: self.handle_function(f_addr)
def continue_run(
self, step=False)
Inheritance:
jitter_mepl
.continue_run
PRE: init_run. Continue the run of the current session until iterator returns or run is set to False. If step is True, run only one time. Return the iterator value
def continue_run(self, step=False): """PRE: init_run. Continue the run of the current session until iterator returns or run is set to False. If step is True, run only one time. Return the iterator value""" while self.run: try: return self.run_iterator.next() except StopIteration: pass self.run_iterator = self.runiter_once(self.pc) if step is True: return None return None
def eval_expr(
self, expr)
Inheritance:
jitter_mepl
.eval_expr
Eval expression @expr in the context of the current instance. Side effects are passed on it
def eval_expr(self, expr): """Eval expression @expr in the context of the current instance. Side effects are passed on it""" self.symbexec.update_engine_from_cpu() ret = self.symbexec.eval_updt_expr(expr) self.symbexec.update_cpu_from_engine() return ret
def get_breakpoint(
self, addr)
Inheritance:
jitter_mepl
.get_breakpoint
Return breakpoints handlers for address @addr @addr: integer
def get_breakpoint(self, addr): """ Return breakpoints handlers for address @addr @addr: integer """ return self.breakpoints_handler.get_callbacks(addr)
def get_exception(
self)
Inheritance:
jitter_mepl
.get_exception
def get_exception(self): return self.cpu.get_exception() | self.vm.get_exception()
def get_stack_arg(
self, n)
Inheritance:
jitter_mepl
.get_stack_arg
def get_stack_arg(self, n): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"] + 2 * n, 2)) return x
def get_str_ansi(
self, addr, max_char=None)
Inheritance:
jitter_mepl
.get_str_ansi
Get ansi str from vm. @addr: address in memory @max_char: maximum len
def get_str_ansi(self, addr, max_char=None): """Get ansi str from vm. @addr: address in memory @max_char: maximum len""" l = 0 tmp = addr while ((max_char is None or l < max_char) and self.vm.get_mem(tmp, 1) != "\x00"): tmp += 1 l += 1 return self.vm.get_mem(addr, l)
def get_str_unic(
self, addr, max_char=None)
Inheritance:
jitter_mepl
.get_str_unic
Get unicode str from vm. @addr: address in memory @max_char: maximum len
def get_str_unic(self, addr, max_char=None): """Get unicode str from vm. @addr: address in memory @max_char: maximum len""" l = 0 tmp = addr while ((max_char is None or l < max_char) and self.vm.get_mem(tmp, 2) != "\x00\x00"): tmp += 2 l += 2 s = self.vm.get_mem(addr, l) s = s[::2] # TODO: real unicode decoding return s
def handle_function(
self, f_addr)
Inheritance:
jitter_mepl
.handle_function
Add a breakpoint which will trigger the function handler
def handle_function(self, f_addr): """Add a breakpoint which will trigger the function handler""" self.add_breakpoint(f_addr, self.handle_lib)
def init_exceptions_handler(
self)
Inheritance:
jitter_mepl
.init_exceptions_handler
Add common exceptions handlers
def init_exceptions_handler(self): "Add common exceptions handlers" def exception_automod(jitter): "Tell the JiT backend to update blocks modified" self.jit.updt_automod_code(jitter.vm) self.vm.set_exception(0) return True def exception_memory_breakpoint(jitter): "Stop the execution and return an identifier" return ExceptionHandle.memoryBreakpoint() self.add_exception_handler(EXCEPT_CODE_AUTOMOD, exception_automod) self.add_exception_handler(EXCEPT_BREAKPOINT_MEMORY, exception_memory_breakpoint)
def init_run(
self, *args, **kwargs)
Inheritance:
jitter_mepl
.init_run
def init_run(self, *args, **kwargs): Jitter.init_run(self, *args, **kwargs) self.cpu.PC = self.pc
def init_stack(
self)
Inheritance:
jitter_mepl
.init_stack
def init_stack(self): self.vm.add_memory_page( self.stack_base, PAGE_READ | PAGE_WRITE, "\x00" * self.stack_size, "Stack") sp = self.arch.getsp(self.attrib) setattr(self.cpu, sp.name, self.stack_base + self.stack_size)
def pop_uint16_t(
self)
Inheritance:
jitter_mepl
.pop_uint16_t
def pop_uint16_t(self): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"], 2)) regs["SP"] += 2 self.cpu.set_gpreg(regs) return x
def push_uint16_t(
self, v)
Inheritance:
jitter_mepl
.push_uint16_t
def push_uint16_t(self, v): regs = self.cpu.get_gpreg() regs["SP"] -= 2 self.cpu.set_gpreg(regs) self.vm.set_mem(regs["SP"], pck16(v))
def remove_breakpoints_by_callback(
self, callback)
Inheritance:
jitter_mepl
.remove_breakpoints_by_callback
Remove callbacks associated with breakpoint. @callback: callback to remove
def remove_breakpoints_by_callback(self, callback): """Remove callbacks associated with breakpoint. @callback: callback to remove """ empty_keys = self.breakpoints_handler.remove_callback(callback) for key in empty_keys: self.jit.remove_disassembly_splits(key)
def run_at(
self, pc)
Inheritance:
jitter_mepl
.run_at
Wrapper on JiT backend. Run the code at PC and return the next PC. @pc: address of code to run
def run_at(self, pc): """Wrapper on JiT backend. Run the code at PC and return the next PC. @pc: address of code to run""" return self.jit.run_at( self.cpu, pc, set(self.breakpoints_handler.callbacks.keys()) )
def runiter_once(
self, pc)
Inheritance:
jitter_mepl
.runiter_once
Iterator on callbacks results on code running from PC. Check exceptions before breakpoints.
def runiter_once(self, pc): """Iterator on callbacks results on code running from PC. Check exceptions before breakpoints.""" self.pc = pc # Callback called before exec if self.exec_cb is not None: res = self.exec_cb(self) if res is not True: yield res # Check breakpoints old_pc = self.pc for res in self.breakpoints_handler.call_callbacks(self.pc, self): if res is not True: if isinstance(res, collections.Iterator): # If the breakpoint is a generator, yield it step by step for tmp in res: yield tmp else: yield res # Check exceptions (raised by breakpoints) exception_flag = self.get_exception() for res in self.exceptions_handler(exception_flag, self): if res is not True: if isinstance(res, collections.Iterator): for tmp in res: yield tmp else: yield res # If a callback changed pc, re call every callback if old_pc != self.pc: return # Exceptions should never be activated before run assert(self.get_exception() == 0) # Run the bloc at PC self.pc = self.run_at(self.pc) # Check exceptions (raised by the execution of the block) exception_flag = self.get_exception() for res in self.exceptions_handler(exception_flag, self): if res is not True: if isinstance(res, collections.Iterator): for tmp in res: yield tmp else: yield res
def set_breakpoint(
self, addr, *args)
Inheritance:
jitter_mepl
.set_breakpoint
Set callbacks associated with addr. @addr: breakpoint address @args: functions with definition (jitter instance)
def set_breakpoint(self, addr, *args): """Set callbacks associated with addr. @addr: breakpoint address @args: functions with definition (jitter instance) """ self.breakpoints_handler.set_callback(addr, *args) self.jit.add_disassembly_splits(addr)
def set_str_ansi(
self, addr, s)
Inheritance:
jitter_mepl
.set_str_ansi
Set an ansi string in memory
def set_str_ansi(self, addr, s): """Set an ansi string in memory""" s = s + "\x00" self.vm.set_mem(addr, s)
def set_str_unic(
self, addr, s)
Inheritance:
jitter_mepl
.set_str_unic
Set an unicode string in memory
def set_str_unic(self, addr, s): """Set an unicode string in memory""" s = "\x00".join(list(s)) + '\x00' * 3 self.vm.set_mem(addr, s)
def set_trace_log(
self, trace_instr=True, trace_regs=True, trace_new_blocks=False)
Inheritance:
jitter_mepl
.set_trace_log
Activate/Deactivate trace log options
@trace_instr: activate instructions tracing log @trace_regs: activate registers tracing log @trace_new_blocks: dump new code blocks log
def set_trace_log(self, trace_instr=True, trace_regs=True, trace_new_blocks=False): """ Activate/Deactivate trace log options @trace_instr: activate instructions tracing log @trace_regs: activate registers tracing log @trace_new_blocks: dump new code blocks log """ # As trace state changes, clear already jitted blocks self.jit.clear_jitted_blocks() self.jit.log_mn = trace_instr self.jit.log_regs = trace_regs self.jit.log_newbloc = trace_new_blocks
class jitter_mepl
class jitter_mepl(Jitter): C_Gen = mep_CGen def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepl(sp), *args, **kwargs) self.vm.set_little_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC def push_uint16_t(self, v): regs = self.cpu.get_gpreg() regs["SP"] -= 2 self.cpu.set_gpreg(regs) self.vm.set_mem(regs["SP"], pck16(v)) def pop_uint16_t(self): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"], 2)) regs["SP"] += 2 self.cpu.set_gpreg(regs) return x def get_stack_arg(self, n): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"] + 2 * n, 2)) return x def init_run(self, *args, **kwargs): Jitter.init_run(self, *args, **kwargs) self.cpu.PC = self.pc
Ancestors (in MRO)
- jitter_mepl
- miasm2.jitter.jitload.Jitter
- __builtin__.object
Class variables
var C_Gen
Static methods
def handle_lib(
jitter)
Resolve the name of the function which cause the handler call. Then call the corresponding handler from users callback.
@staticmethod def handle_lib(jitter): """Resolve the name of the function which cause the handler call. Then call the corresponding handler from users callback. """ fname = jitter.libs.fad2cname[jitter.pc] if fname in jitter.user_globals: func = jitter.user_globals[fname] else: log.debug('%r', fname) raise ValueError('unknown api', hex(jitter.pc), repr(fname)) ret = func(jitter) jitter.pc = getattr(jitter.cpu, jitter.ir_arch.pc.name) # Don't break on a None return if ret is None: return True else: return ret
Methods
def __init__(
self, *args, **kwargs)
def __init__(self, *args, **kwargs): sp = LocationDB() Jitter.__init__(self, ir_mepl(sp), *args, **kwargs) self.vm.set_little_endian() self.ir_arch.jit_pc = self.ir_arch.arch.regs.PC
def add_breakpoint(
self, addr, callback)
Add a callback associated with addr. @addr: breakpoint address @callback: function with definition (jitter instance)
def add_breakpoint(self, addr, callback): """Add a callback associated with addr. @addr: breakpoint address @callback: function with definition (jitter instance) """ self.breakpoints_handler.add_callback(addr, callback) self.jit.add_disassembly_splits(addr) # De-jit previously jitted blocks self.jit.updt_automod_code_range(self.vm, [(addr, addr)])
def add_exception_handler(
self, flag, callback)
Add a callback associated with an exception flag. @flag: bitflag @callback: function with definition (jitter instance)
def add_exception_handler(self, flag, callback): """Add a callback associated with an exception flag. @flag: bitflag @callback: function with definition (jitter instance) """ self.exceptions_handler.add_callback(flag, callback)
def add_lib_handler(
self, libs, user_globals=None)
Add a function to handle libs call with breakpoints @libs: libimp instance @user_globals: dictionary for defined user function
def add_lib_handler(self, libs, user_globals=None): """Add a function to handle libs call with breakpoints @libs: libimp instance @user_globals: dictionary for defined user function """ if user_globals is None: user_globals = {} self.libs = libs self.user_globals = user_globals for f_addr in libs.fad2cname: self.handle_function(f_addr)
def continue_run(
self, step=False)
PRE: init_run. Continue the run of the current session until iterator returns or run is set to False. If step is True, run only one time. Return the iterator value
def continue_run(self, step=False): """PRE: init_run. Continue the run of the current session until iterator returns or run is set to False. If step is True, run only one time. Return the iterator value""" while self.run: try: return self.run_iterator.next() except StopIteration: pass self.run_iterator = self.runiter_once(self.pc) if step is True: return None return None
def eval_expr(
self, expr)
Eval expression @expr in the context of the current instance. Side effects are passed on it
def eval_expr(self, expr): """Eval expression @expr in the context of the current instance. Side effects are passed on it""" self.symbexec.update_engine_from_cpu() ret = self.symbexec.eval_updt_expr(expr) self.symbexec.update_cpu_from_engine() return ret
def get_breakpoint(
self, addr)
Return breakpoints handlers for address @addr @addr: integer
def get_breakpoint(self, addr): """ Return breakpoints handlers for address @addr @addr: integer """ return self.breakpoints_handler.get_callbacks(addr)
def get_exception(
self)
def get_exception(self): return self.cpu.get_exception() | self.vm.get_exception()
def get_stack_arg(
self, n)
def get_stack_arg(self, n): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"] + 2 * n, 2)) return x
def get_str_ansi(
self, addr, max_char=None)
Get ansi str from vm. @addr: address in memory @max_char: maximum len
def get_str_ansi(self, addr, max_char=None): """Get ansi str from vm. @addr: address in memory @max_char: maximum len""" l = 0 tmp = addr while ((max_char is None or l < max_char) and self.vm.get_mem(tmp, 1) != "\x00"): tmp += 1 l += 1 return self.vm.get_mem(addr, l)
def get_str_unic(
self, addr, max_char=None)
Get unicode str from vm. @addr: address in memory @max_char: maximum len
def get_str_unic(self, addr, max_char=None): """Get unicode str from vm. @addr: address in memory @max_char: maximum len""" l = 0 tmp = addr while ((max_char is None or l < max_char) and self.vm.get_mem(tmp, 2) != "\x00\x00"): tmp += 2 l += 2 s = self.vm.get_mem(addr, l) s = s[::2] # TODO: real unicode decoding return s
def handle_function(
self, f_addr)
Add a breakpoint which will trigger the function handler
def handle_function(self, f_addr): """Add a breakpoint which will trigger the function handler""" self.add_breakpoint(f_addr, self.handle_lib)
def init_exceptions_handler(
self)
Add common exceptions handlers
def init_exceptions_handler(self): "Add common exceptions handlers" def exception_automod(jitter): "Tell the JiT backend to update blocks modified" self.jit.updt_automod_code(jitter.vm) self.vm.set_exception(0) return True def exception_memory_breakpoint(jitter): "Stop the execution and return an identifier" return ExceptionHandle.memoryBreakpoint() self.add_exception_handler(EXCEPT_CODE_AUTOMOD, exception_automod) self.add_exception_handler(EXCEPT_BREAKPOINT_MEMORY, exception_memory_breakpoint)
def init_run(
self, *args, **kwargs)
def init_run(self, *args, **kwargs): Jitter.init_run(self, *args, **kwargs) self.cpu.PC = self.pc
def init_stack(
self)
def init_stack(self): self.vm.add_memory_page( self.stack_base, PAGE_READ | PAGE_WRITE, "\x00" * self.stack_size, "Stack") sp = self.arch.getsp(self.attrib) setattr(self.cpu, sp.name, self.stack_base + self.stack_size)
def pop_uint16_t(
self)
def pop_uint16_t(self): regs = self.cpu.get_gpreg() x = upck16(self.vm.get_mem(regs["SP"], 2)) regs["SP"] += 2 self.cpu.set_gpreg(regs) return x
def push_uint16_t(
self, v)
def push_uint16_t(self, v): regs = self.cpu.get_gpreg() regs["SP"] -= 2 self.cpu.set_gpreg(regs) self.vm.set_mem(regs["SP"], pck16(v))
def remove_breakpoints_by_callback(
self, callback)
Remove callbacks associated with breakpoint. @callback: callback to remove
def remove_breakpoints_by_callback(self, callback): """Remove callbacks associated with breakpoint. @callback: callback to remove """ empty_keys = self.breakpoints_handler.remove_callback(callback) for key in empty_keys: self.jit.remove_disassembly_splits(key)
def run_at(
self, pc)
Wrapper on JiT backend. Run the code at PC and return the next PC. @pc: address of code to run
def run_at(self, pc): """Wrapper on JiT backend. Run the code at PC and return the next PC. @pc: address of code to run""" return self.jit.run_at( self.cpu, pc, set(self.breakpoints_handler.callbacks.keys()) )
def runiter_once(
self, pc)
Iterator on callbacks results on code running from PC. Check exceptions before breakpoints.
def runiter_once(self, pc): """Iterator on callbacks results on code running from PC. Check exceptions before breakpoints.""" self.pc = pc # Callback called before exec if self.exec_cb is not None: res = self.exec_cb(self) if res is not True: yield res # Check breakpoints old_pc = self.pc for res in self.breakpoints_handler.call_callbacks(self.pc, self): if res is not True: if isinstance(res, collections.Iterator): # If the breakpoint is a generator, yield it step by step for tmp in res: yield tmp else: yield res # Check exceptions (raised by breakpoints) exception_flag = self.get_exception() for res in self.exceptions_handler(exception_flag, self): if res is not True: if isinstance(res, collections.Iterator): for tmp in res: yield tmp else: yield res # If a callback changed pc, re call every callback if old_pc != self.pc: return # Exceptions should never be activated before run assert(self.get_exception() == 0) # Run the bloc at PC self.pc = self.run_at(self.pc) # Check exceptions (raised by the execution of the block) exception_flag = self.get_exception() for res in self.exceptions_handler(exception_flag, self): if res is not True: if isinstance(res, collections.Iterator): for tmp in res: yield tmp else: yield res
def set_breakpoint(
self, addr, *args)
Set callbacks associated with addr. @addr: breakpoint address @args: functions with definition (jitter instance)
def set_breakpoint(self, addr, *args): """Set callbacks associated with addr. @addr: breakpoint address @args: functions with definition (jitter instance) """ self.breakpoints_handler.set_callback(addr, *args) self.jit.add_disassembly_splits(addr)
def set_str_ansi(
self, addr, s)
Set an ansi string in memory
def set_str_ansi(self, addr, s): """Set an ansi string in memory""" s = s + "\x00" self.vm.set_mem(addr, s)
def set_str_unic(
self, addr, s)
Set an unicode string in memory
def set_str_unic(self, addr, s): """Set an unicode string in memory""" s = "\x00".join(list(s)) + '\x00' * 3 self.vm.set_mem(addr, s)
def set_trace_log(
self, trace_instr=True, trace_regs=True, trace_new_blocks=False)
Activate/Deactivate trace log options
@trace_instr: activate instructions tracing log @trace_regs: activate registers tracing log @trace_new_blocks: dump new code blocks log
def set_trace_log(self, trace_instr=True, trace_regs=True, trace_new_blocks=False): """ Activate/Deactivate trace log options @trace_instr: activate instructions tracing log @trace_regs: activate registers tracing log @trace_new_blocks: dump new code blocks log """ # As trace state changes, clear already jitted blocks self.jit.clear_jitted_blocks() self.jit.log_mn = trace_instr self.jit.log_regs = trace_regs self.jit.log_newbloc = trace_new_blocks
class mep_CGen
Translate a bloc containing MeP instructions to C
Note: it is used to emulate the *REPEAT instructions
class mep_CGen(CGen): """ Translate a bloc containing MeP instructions to C Note: it is used to emulate the *REPEAT instructions """ def __init__(self, ir_arch): self.ir_arch = ir_arch self.PC = self.ir_arch.arch.regs.PC self.translator = TranslatorC(self.ir_arch.loc_db) self.init_arch_C() def gen_pre_code(self, attrib): """Generate C code inserted before the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_pre_code(attrib) # Set the PC register value explicitly out.append("mycpu->PC = 0x%X;" % attrib.instr.offset) out.append("mycpu->last_addr = mycpu->PC;"); return out def gen_post_code(self, attrib): """Generate C code inserted after the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_post_code(attrib) # Implement the *REPEAT instructions logics tmp = r""" /* *REPEAT instructions logic */ { uint32_t is_repeat_end = mycpu->is_repeat_end; mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1)); if (is_repeat_end && !mycpu->take_jmp && (mycpu->in_erepeat || mycpu->RPC)) { if (mycpu->RPC) mycpu->RPC --; //printf("Go repeat %X\n", mycpu->RPB); DST_value = mycpu->RPB; BlockDst->address = mycpu->RPB; return JIT_RET_NO_EXCEPTION; } } """ out += tmp.split('`\n') return out
Ancestors (in MRO)
- mep_CGen
- miasm2.jitter.codegen.CGen
- __builtin__.object
Class variables
var CODE_BAD_BLOCK
var CODE_CPU_EXCEPTION_POST_INSTR
var CODE_EXCEPTION_AT_INSTR
var CODE_EXCEPTION_MEM_AT_INSTR
var CODE_INIT
var CODE_RETURN_EXCEPTION
var CODE_RETURN_NO_EXCEPTION
var CODE_VM_EXCEPTION_POST_INSTR
Instance variables
var PC
var ir_arch
var translator
Methods
def __init__(
self, ir_arch)
def __init__(self, ir_arch): self.ir_arch = ir_arch self.PC = self.ir_arch.arch.regs.PC self.translator = TranslatorC(self.ir_arch.loc_db) self.init_arch_C()
def add_label_index(
self, dst2index, loc_key)
Insert @lbl to the dictionnary @dst2index with a uniq value @dst2index: LocKey -> uniq value @loc_key: LocKey istance
def add_label_index(self, dst2index, loc_key): """Insert @lbl to the dictionnary @dst2index with a uniq value @dst2index: LocKey -> uniq value @loc_key: LocKey istance""" if loc_key not in dst2index: dst2index[loc_key] = len(dst2index)
def add_local_var(
self, dst_var, dst_index, expr)
Add local varaible used to store temporay result @dst_var: dictionnary of Expr -> local_var_expr @dst_index : dictionnary of size -> local var count @expr: Expression source
def add_local_var(self, dst_var, dst_index, expr): """ Add local varaible used to store temporay result @dst_var: dictionnary of Expr -> local_var_expr @dst_index : dictionnary of size -> local var count @expr: Expression source """ size = expr.size if size < 8: size = 8 if size not in dst_index: raise RuntimeError("Unsupported operand size %s", size) var_num = dst_index[size] dst = ExprId("var_%.2d_%.2d" % (size, var_num), size) dst_index[size] += 1 dst_var[expr] = dst return dst
def assignblk_to_irbloc(
self, instr, assignblk)
Ensure IRDst is always set in the head @assignblk of the @instr @instr: an instruction instance @assignblk: Assignblk instance
def assignblk_to_irbloc(self, instr, assignblk): """ Ensure IRDst is always set in the head @assignblk of the @instr @instr: an instruction instance @assignblk: Assignblk instance """ new_assignblk = dict(assignblk) if self.ir_arch.IRDst not in assignblk: offset = instr.offset + instr.l loc_key = self.ir_arch.loc_db.get_or_create_offset_location(offset) dst = ExprLoc(loc_key, self.ir_arch.IRDst.size) new_assignblk[self.ir_arch.IRDst] = dst irs = [AssignBlock(new_assignblk, instr)] return IRBlock(self.ir_arch.get_loc_key_for_instr(instr), irs)
def block2assignblks(
self, block)
Return the list of irblocks for a native @block @block: AsmBlock
def block2assignblks(self, block): """ Return the list of irblocks for a native @block @block: AsmBlock """ irblocks_list = [] for instr in block.lines: assignblk_head, assignblks_extra = self.ir_arch.instr2ir(instr) # Keep result in ordered list as first element is the assignblk head # The remainings order is not really important irblock_head = self.assignblk_to_irbloc(instr, assignblk_head) irblocks = [irblock_head] + assignblks_extra # Simplify high level operators out = [] for irblock in irblocks: new_irblock = irblock.simplify(expr_simp_high_to_explicit)[1] out.append(new_irblock) irblocks = out for irblock in irblocks: assert irblock.dst is not None irblocks_list.append(irblocks) return irblocks_list
def dst_to_c(
self, src)
Translate Expr @src into C code
def dst_to_c(self, src): """Translate Expr @src into C code""" if not isinstance(src, Expr): src = ExprInt(src, self.PC.size) return self.id_to_c(src)
def gen_assignblk_dst(
self, dst)
Generate C code to handle instruction destination @dst: instruction destination Expr
def gen_assignblk_dst(self, dst): """Generate C code to handle instruction destination @dst: instruction destination Expr""" dst2index = {} (ret, retb) = self.traverse_expr_dst(dst, dst2index) ret = "DST_case = %s;" % ret retb = 'DST_value = %s;' % retb return ['// %s' % dst2index, '%s' % ret, '%s' % retb], dst2index
def gen_bad_block(
self)
Generate the C code for a bad_block instance
def gen_bad_block(self): """ Generate the C code for a bad_block instance """ return self.CODE_BAD_BLOCK.split("\n")
def gen_c(
self, block, log_mn=False, log_regs=False)
Generate the C code for the @block and return it as a list of lines @log_mn: log mnemonics @log_regs: log registers
def gen_c(self, block, log_mn=False, log_regs=False): """ Generate the C code for the @block and return it as a list of lines @log_mn: log mnemonics @log_regs: log registers """ if isinstance(block, AsmBlockBad): return self.gen_bad_block() irblocks_list = self.block2assignblks(block) out, instr_offsets = self.gen_init(block) assert len(block.lines) == len(irblocks_list) for instr, irblocks in zip(block.lines, irblocks_list): instr_attrib, irblocks_attributes = self.get_attributes(instr, irblocks, log_mn, log_regs) for index, irblock in enumerate(irblocks): new_irblock = self.ir_arch.irbloc_fix_regs_for_mode(irblock, self.ir_arch.attrib) label = str(new_irblock.loc_key) out.append("%-40s // %.16X %s" % (label + ":", instr.offset, instr)) if index == 0: out += self.gen_pre_code(instr_attrib) out += self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, new_irblock) out += self.gen_finalize(block) return ['\t' + line for line in out]
def gen_c_assignments(
self, assignblk)
Return C informations used to generate the C code of the @assignblk @assignblk: an AssignBlock instance
def gen_c_assignments(self, assignblk): """ Return C informations used to generate the C code of the @assignblk @assignblk: an AssignBlock instance """ c_var = [] c_main = [] c_mem = [] c_updt = [] c_prefetch = [] dst_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0} dst_var = {} prefetchers = self.get_mem_prefetch(assignblk) for expr, prefetcher in sorted(prefetchers.iteritems()): str_src = self.id_to_c(expr) str_dst = self.id_to_c(prefetcher) c_prefetch.append('%s = %s;' % (str_dst, str_src)) for var in prefetchers.itervalues(): if var.size <= self.translator.NATIVE_INT_MAX_SIZE: c_var.append("uint%d_t %s;" % (var.size, var)) else: c_var.append("bn_t %s; // %d" % (var, var.size)) for dst, src in sorted(assignblk.iteritems()): src = src.replace_expr(prefetchers) if dst == self.ir_arch.IRDst: pass elif isinstance(dst, ExprId): new_dst = self.add_local_var(dst_var, dst_index, dst) if dst in self.ir_arch.arch.regs.regs_flt_expr: # Dont mask float affectation c_main.append( '%s = (%s);' % (self.id_to_c(new_dst), self.id_to_c(src))) elif new_dst.size <= self.translator.NATIVE_INT_MAX_SIZE: c_main.append( '%s = (%s)&%s;' % (self.id_to_c(new_dst), self.id_to_c(src), SIZE_TO_MASK[src.size])) else: c_main.append( '%s = bignum_mask(%s, %d);' % ( self.id_to_c(new_dst), self.id_to_c(src), src.size ) ) elif isinstance(dst, ExprMem): ptr = dst.arg.replace_expr(prefetchers) if ptr.size <= self.translator.NATIVE_INT_MAX_SIZE: new_dst = ExprMem(ptr, dst.size) str_dst = self.id_to_c(new_dst).replace('MEM_LOOKUP', 'MEM_WRITE') c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src))) else: ptr_str = self.id_to_c(ptr) if ptr.size <= self.translator.NATIVE_INT_MAX_SIZE: c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src))) else: if src.size <= self.translator.NATIVE_INT_MAX_SIZE: c_mem.append('MEM_WRITE_BN_INT(jitcpu, %d, %s, %s);' % ( src.size, ptr_str, self.id_to_c(src)) ) else: c_mem.append('MEM_WRITE_BN_BN(jitcpu, %d, %s, %s);' % ( src.size, ptr_str, self.id_to_c(src)) ) else: raise ValueError("Unknown dst") for dst, new_dst in dst_var.iteritems(): if dst == self.ir_arch.IRDst: continue c_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst))) if dst.size <= self.translator.NATIVE_INT_MAX_SIZE: c_var.append("uint%d_t %s;" % (new_dst.size, new_dst)) else: c_var.append("bn_t %s; // %d" % (new_dst, new_dst.size)) return c_prefetch, c_var, c_main, c_mem, c_updt
def gen_c_code(
self, attrib, c_dst, c_assignmnts)
Generate the C code for assignblk. @attrib: Attributes instance @c_dst: irdst C code
def gen_c_code(self, attrib, c_dst, c_assignmnts): """ Generate the C code for assignblk. @attrib: Attributes instance @c_dst: irdst C code """ c_prefetch, c_var, c_main, c_mem, c_updt = c_assignmnts out = [] out.append("{") out.append("// var") out += c_var out.append("// Prefetch") out += c_prefetch out.append("// Dst") out += c_dst out.append("// Main") out += c_main out.append("// Check op/mem exceptions") # Check memory access if assignblk has memory read if c_prefetch: out += self.gen_check_memory_exception(attrib.instr.offset) out.append("// Mem updt") out += c_mem out.append("// Check exception Mem write") # Check memory write exceptions if attrib.mem_write: out += self.gen_check_memory_exception(attrib.instr.offset) out.append("// Updt") out += c_updt out.append("// Checks exception") # Check post assignblk exception flags if attrib.set_exception: out += self.gen_check_cpu_exception(attrib.instr.offset) out.append("}") return out
def gen_check_cpu_exception(
self, address)
Generate C code to check cpu exceptions @address: address of the faulty instruction
def gen_check_cpu_exception(self, address): """Generate C code to check cpu exceptions @address: address of the faulty instruction""" dst = self.dst_to_c(address) return (self.CODE_EXCEPTION_AT_INSTR % (self.C_PC, dst, dst)).split('\n')
def gen_check_memory_exception(
self, address)
Generate C code to check memory exceptions @address: address of the faulty instruction
def gen_check_memory_exception(self, address): """Generate C code to check memory exceptions @address: address of the faulty instruction""" dst = self.dst_to_c(address) return (self.CODE_EXCEPTION_MEM_AT_INSTR % (self.C_PC, dst, dst)).split('\n')
def gen_dst_goto(
self, attrib, instr_offsets, dst2index)
Generate code for possible @dst2index.
@attrib: an Attributes instance @instr_offsets: list of instructions offsets @dst2index: link from destination to index
def gen_dst_goto(self, attrib, instr_offsets, dst2index): """ Generate code for possible @dst2index. @attrib: an Attributes instance @instr_offsets: list of instructions offsets @dst2index: link from destination to index """ if not dst2index: return [] out = [] out.append('switch(DST_case) {') stopcase = False for dst, index in sorted(dst2index.iteritems(), key=lambda lblindex: lblindex[1]): if index == -1: # Handle '-1' case only once if not stopcase: stopcase = True else: continue out.append('\tcase %d:' % index) out += self.gen_goto_code(attrib, instr_offsets, dst) out.append('\t\tbreak;') out.append('};') return out
def gen_finalize(
self, block)
Generate the C code for the final block instruction
def gen_finalize(self, block): """ Generate the C code for the final block instruction """ loc_key = self.get_block_post_label(block) offset = self.ir_arch.loc_db.get_location_offset(loc_key) dst = self.dst_to_c(offset) code = self.CODE_RETURN_NO_EXCEPTION % (loc_key, self.C_PC, dst, dst) return code.split('\n')
def gen_goto_code(
self, attrib, instr_offsets, dst)
Generate C code for a potential destination @dst @attrib: instruction Attributes @instr_offsets: instructions offsets list @dst: potential instruction destination
def gen_goto_code(self, attrib, instr_offsets, dst): """Generate C code for a potential destination @dst @attrib: instruction Attributes @instr_offsets: instructions offsets list @dst: potential instruction destination""" out = [] if isinstance(dst, Expr): out += self.gen_post_code(attrib) out.append('BlockDst->address = DST_value;') out += self.gen_post_instr_checks(attrib) out.append('\t\treturn JIT_RET_NO_EXCEPTION;') return out assert isinstance(dst, LocKey) offset = self.ir_arch.loc_db.get_location_offset(dst) if offset is None: # Generate goto for local labels return ['goto %s;' % dst] if (offset > attrib.instr.offset and offset in instr_offsets): # Only generate goto for next instructions. # (consecutive instructions) out += self.gen_post_code(attrib) out += self.gen_post_instr_checks(attrib) out.append('goto %s;' % dst) else: out += self.gen_post_code(attrib) out.append('BlockDst->address = DST_value;') out += self.gen_post_instr_checks(attrib) out.append('\t\treturn JIT_RET_NO_EXCEPTION;') return out
def gen_init(
self, block)
Generate the init C code for a @block @block: an asm_bloc instance
def gen_init(self, block): """ Generate the init C code for a @block @block: an asm_bloc instance """ instr_offsets = [line.offset for line in block.lines] post_label = self.get_block_post_label(block) post_offset = self.ir_arch.loc_db.get_location_offset(post_label) instr_offsets.append(post_offset) lbl_start = block.loc_key return (self.CODE_INIT % lbl_start).split("\n"), instr_offsets
def gen_irblock(
self, instr_attrib, attributes, instr_offsets, irblock)
Generate the C code for an @irblock @irblock: an irbloc instance @attributes: an Attributes instance list
def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock): """ Generate the C code for an @irblock @irblock: an irbloc instance @attributes: an Attributes instance list """ out = [] dst2index = None for index, assignblk in enumerate(irblock): if index == irblock.dst_linenb: c_dst, dst2index = self.gen_assignblk_dst(irblock.dst) else: c_dst = [] c_assignmnts = self.gen_c_assignments(assignblk) out += self.gen_c_code(attributes[index], c_dst, c_assignmnts) if dst2index: out.append("// Set irdst") # Gen goto on irdst set out += self.gen_dst_goto(instr_attrib, instr_offsets, dst2index) return out
def gen_post_code(
self, attrib)
Generate C code inserted after the current bloc
def gen_post_code(self, attrib): """Generate C code inserted after the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_post_code(attrib) # Implement the *REPEAT instructions logics tmp = r""" /* *REPEAT instructions logic */ { uint32_t is_repeat_end = mycpu->is_repeat_end; mycpu->is_repeat_end = !!(mycpu->last_addr == (mycpu->RPE&~0x1)); if (is_repeat_end && !mycpu->take_jmp && (mycpu->in_erepeat || mycpu->RPC)) { if (mycpu->RPC) mycpu->RPC --; //printf("Go repeat %X\n", mycpu->RPB); DST_value = mycpu->RPB; BlockDst->address = mycpu->RPB; return JIT_RET_NO_EXCEPTION; } } """ out += tmp.split('`\n') return out
def gen_post_instr_checks(
self, attrib)
Generate C code for handling potential exceptions @attrib: Attributes instance
def gen_post_instr_checks(self, attrib): """Generate C code for handling potential exceptions @attrib: Attributes instance""" out = [] if attrib.mem_read | attrib.mem_write: out += (self.CODE_VM_EXCEPTION_POST_INSTR % (self.C_PC)).split('\n') if attrib.set_exception: out += (self.CODE_CPU_EXCEPTION_POST_INSTR % (self.C_PC)).split('\n') if attrib.mem_read | attrib.mem_write: out.append("reset_memory_access(&(jitcpu->pyvm->vm_mngr));") return out
def gen_pre_code(
self, attrib)
Generate C code inserted before the current bloc
def gen_pre_code(self, attrib): """Generate C code inserted before the current bloc""" # Call the base class method out = super(mep_CGen, self).gen_pre_code(attrib) # Set the PC register value explicitly out.append("mycpu->PC = 0x%X;" % attrib.instr.offset) out.append("mycpu->last_addr = mycpu->PC;"); return out
def get_attributes(
self, instr, irblocks, log_mn=False, log_regs=False)
Get the carateristics of each @irblocks. Returns the corresponding attributes object. @irblock: a list of irbloc instance @log_mn: generate code to log instructions @log_regs: generate code to log registers states
def get_attributes(self, instr, irblocks, log_mn=False, log_regs=False): """ Get the carateristics of each @irblocks. Returns the corresponding attributes object. @irblock: a list of irbloc instance @log_mn: generate code to log instructions @log_regs: generate code to log registers states """ instr_attrib = Attributes(log_mn, log_regs) instr_attrib.instr = instr irblocks_attributes = [] for irblock in irblocks: attributes = [] irblocks_attributes.append(attributes) for assignblk in irblock: attrib = Attributes(log_mn, log_regs) attributes.append(attrib) self.get_caracteristics(assignblk, attrib) attrib.instr = instr instr_attrib.mem_read |= attrib.mem_read instr_attrib.mem_write |= attrib.mem_write instr_attrib.set_exception |= attrib.set_exception return instr_attrib, irblocks_attributes
def get_block_post_label(
self, block)
Get label next to the @block @block: AsmBlock instance
def get_block_post_label(self, block): """Get label next to the @block @block: AsmBlock instance""" last_instr = block.lines[-1] offset = last_instr.offset + last_instr.l return self.ir_arch.loc_db.get_or_create_offset_location(offset)
def get_caracteristics(
self, assignblk, attrib)
Set the carateristics in @attrib according to the @assignblk @assignblk: an AssignBlock instance @attrib: an Attributes instance
def get_caracteristics(self, assignblk, attrib): """ Set the carateristics in @attrib according to the @assignblk @assignblk: an AssignBlock instance @attrib: an Attributes instance """ # Check explicit exception raising attrib.set_exception = self.ir_arch.arch.regs.exception_flags in assignblk element_read = assignblk.get_r(mem_read=True) # Check mem read attrib.mem_read = any(isinstance(expr, ExprMem) for expr in element_read) # Check mem write attrib.mem_write = any(isinstance(dst, ExprMem) for dst in assignblk)
def get_mem_prefetch(
self, assignblk)
Generate temporary variables used to fetch memory used in the @assignblk Return a dictionnary: ExprMem -> temporary variable @assignblk: AssignBlock instance
def get_mem_prefetch(self, assignblk): """ Generate temporary variables used to fetch memory used in the @assignblk Return a dictionnary: ExprMem -> temporary variable @assignblk: AssignBlock instance """ mem_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0} mem_var = {} # Prefetch memory read for expr in assignblk.get_r(mem_read=True): if not isinstance(expr, ExprMem): continue var_num = mem_index[expr.size] mem_index[expr.size] += 1 var = ExprId( "prefetch_%.2d_%.2d" % (expr.size, var_num), expr.size ) mem_var[expr] = var # Generate memory prefetch return mem_var
def id_to_c(
self, expr)
Translate Expr @expr into corresponding C code
def id_to_c(self, expr): """Translate Expr @expr into corresponding C code""" return self.translator.from_expr(self.patch_c_id(expr))
def init_arch_C(
self)
Iinitialize jitter internals
def init_arch_C(self): """Iinitialize jitter internals""" self.id_to_c_id = {} for reg in self.ir_arch.arch.regs.all_regs_ids: self.id_to_c_id[reg] = ExprId('mycpu->%s' % reg, reg.size) self.C_PC = self.id_to_c(self.PC)
def patch_c_id(
self, expr)
Replace ExprId in @expr with corresponding C variables
def patch_c_id(self, expr): """Replace ExprId in @expr with corresponding C variables""" return expr.replace_expr(self.id_to_c_id)
def traverse_expr_dst(
self, expr, dst2index)
Generate the index of the destination label for the @expr @dst2index: dictionnary to link label to its index
def traverse_expr_dst(self, expr, dst2index): """ Generate the index of the destination label for the @expr @dst2index: dictionnary to link label to its index """ if isinstance(expr, ExprCond): src1, src1b = self.traverse_expr_dst(expr.src1, dst2index) src2, src2b = self.traverse_expr_dst(expr.src2, dst2index) cond = self.id_to_c(expr.cond) if not expr.cond.size <= self.translator.NATIVE_INT_MAX_SIZE: cond = "(!bignum_is_zero(%s))" % cond return ("((%s)?(%s):(%s))" % (cond, src1, src2), "((%s)?(%s):(%s))" % (cond, src1b, src2b)) if isinstance(expr, ExprInt): offset = int(expr) loc_key = self.ir_arch.loc_db.get_or_create_offset_location(offset) self.add_label_index(dst2index, loc_key) value, int_size = int_size_to_bn(offset, 64) out = hex(offset) return ("%s" % dst2index[loc_key], out) if expr.is_loc(): loc_key = expr.loc_key offset = self.ir_arch.loc_db.get_location_offset(expr.loc_key) if offset is not None: self.add_label_index(dst2index, loc_key) value, int_size = int_size_to_bn(offset, 64) out = hex(offset) return ("%s" % dst2index[loc_key], out) self.add_label_index(dst2index, loc_key) value, int_size = int_size_to_bn(0, 64) out = hex(0) return ("%s" % dst2index[loc_key], out) dst2index[expr] = -1 return ("-1", self.id_to_c(expr))