about summary refs log tree commit diff stats
path: root/miasm2/jitter/jitcore.py
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2/jitter/jitcore.py')
-rw-r--r--miasm2/jitter/jitcore.py252
1 files changed, 252 insertions, 0 deletions
diff --git a/miasm2/jitter/jitcore.py b/miasm2/jitter/jitcore.py
new file mode 100644
index 00000000..34ae3be9
--- /dev/null
+++ b/miasm2/jitter/jitcore.py
@@ -0,0 +1,252 @@
+#
+# Copyright (C) 2011 EADS France, Fabrice Desclaux <fabrice.desclaux@eads.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+from miasm2.core import asmbloc
+from miasm2.core.interval import interval
+from csts import *
+
+
+class JitCore(object):
+
+    "JiT management. This is an abstract class"
+
+    def __init__(self, my_ir, bs=None):
+        """Initialise a JitCore instance.
+        @my_ir: ir instance for current architecture
+        @bs: bitstream
+        """
+
+        self.my_ir = my_ir
+        self.bs = bs
+        self.known_blocs = {}
+        self.lbl2jitbloc = {}
+        self.lbl2bloc = {}
+        self.log_mn = False
+        self.log_regs = False
+        self.log_newbloc = False
+        self.segm_to_do = set()
+        self.job_done = set()
+        self.jitcount = 0
+        self.addr2obj = {}
+        self.addr2objref = {}
+        self.blocs_mem_interval = interval()
+        self.disasm_cb = None
+        self.split_dis = set()
+
+        self.options = {"jit_maxline": 50  # Maximum number of line jitted
+                        }
+
+    def set_options(self, **kwargs):
+        "Set options relative to the backend"
+
+        self.options.update(kwargs)
+
+    def add_disassembly_splits(self, *args):
+        """The disassembly engine will stop on address in args if they
+        are not at the block beginning"""
+        self.split_dis.update(set(args))
+
+    def remove_disassembly_splits(self, *args):
+        """The disassembly engine will no longer stop on address in args"""
+        self.split_dis.difference_update(set(args))
+
+    def load(self, arch, attrib):
+        "Initialise the Jitter according to arch and attrib"
+
+        raise Exception("DO NOT instanciate JitCore")
+
+    def __get_bloc_min_max(self, cur_bloc):
+        "Update cur_bloc to set min/max address"
+
+        if cur_bloc.lines:
+            cur_bloc.ad_min = cur_bloc.lines[0].offset
+            cur_bloc.ad_max = cur_bloc.lines[-1].offset + cur_bloc.lines[-1].l
+
+    def __add_bloc_to_mem_interval(self, vm, bloc):
+        "Update vm to include bloc addresses in its memory range"
+
+        self.blocs_mem_interval += interval([(bloc.ad_min, bloc.ad_max - 1)])
+
+        vm.vm_reset_code_bloc_pool()
+        for a, b in self.blocs_mem_interval:
+            vm.vm_add_code_bloc(a, b + 1)
+
+    def jitirblocs(self, label, irblocs):
+        """JiT a group of irblocs.
+        @label: the label of the irblocs
+        @irblocs: a gorup of irblocs
+        """
+
+        raise Exception("DO NOT instanciate JitCore")
+
+    def add_bloc(self, b):
+        """Add a bloc to JiT and JiT it.
+        @b: the bloc to add
+        """
+
+        irblocs = self.my_ir.add_bloc(b, gen_pc_updt = True)
+        b.irblocs = irblocs
+        self.jitirblocs(b.label, irblocs)
+
+    def __disbloc(self, addr, cpu, vm):
+        "Disassemble a new bloc and JiT it"
+
+        # Get the bloc
+        if isinstance(addr, asmbloc.asm_label):
+            addr = addr.offset
+
+        l = self.my_ir.symbol_pool.getby_offset_create(addr)
+        cur_bloc = asmbloc.asm_bloc(l)
+
+        # Disassemble it
+        try:
+            asmbloc.dis_bloc(self.my_ir.arch, self.bs, cur_bloc, addr,
+                             set(), self.my_ir.symbol_pool, [],
+                             follow_call=False, patch_instr_symb=True,
+                             dontdis_retcall=False,
+                             lines_wd=self.options["jit_maxline"],
+                             # max 10 asm lines
+                             attrib=self.my_ir.attrib,
+                             split_dis=self.split_dis)
+        except IOError:
+            # vm_exception_flag is set
+            pass
+
+        # Logging
+        if self.log_newbloc:
+            print cur_bloc
+        if self.disasm_cb is not None:
+            self.disasm_cb(cur_bloc)
+        # Update label -> bloc
+        self.lbl2bloc[l] = cur_bloc
+
+        # Store min/max bloc address needed in jit automod code
+        self.__get_bloc_min_max(cur_bloc)
+
+        # JiT it
+        self.add_bloc(cur_bloc)
+
+        # Update jitcode mem range
+        self.__add_bloc_to_mem_interval(vm, cur_bloc)
+
+    def jit_call(self, label, cpu, vmmngr):
+        """Call the function label with cpu and vmmngr states
+        @label: function's label
+        @cpu: address of the cpu state structure
+        @vmmngr: address of the memory state structure
+        """
+
+        fc_ptr = self.lbl2jitbloc[label]
+        return self.exec_wrapper(fc_ptr, cpu, vmmngr)
+
+    def runbloc(self, cpu, vm, lbl):
+        """Run the bloc starting at lbl.
+        @cpu: JitCpu instance
+        @vm: VmMngr instance
+        @lbl: target label
+        """
+
+        if lbl is None:
+            lbl = cpu.vm_get_gpreg()[self.my_ir.pc.name]
+
+        if not lbl in self.lbl2jitbloc:
+            # Need to JiT the bloc
+            self.__disbloc(lbl, cpu, vm)
+
+        # Run the bloc and update cpu/vmmngr state
+        ret = self.jit_call(lbl, cpu.cpu, vm.vmmngr)
+
+        return ret
+
+    def __blocs2memrange(self, blocs):
+        """Return an interval instance standing for blocs addresses
+        @blocs: list of asm_bloc instances
+        """
+
+        mem_range = interval()
+
+        for b in blocs:
+            mem_range += interval([(b.ad_min, b.ad_max - 1)])
+
+        return mem_range
+
+    def __updt_jitcode_mem_range(self, vm):
+        """Rebuild the VM blocs address memory range
+        @vm: VmMngr instance
+        """
+
+        # Reset the current pool
+        vm.vm_reset_code_bloc_pool()
+
+        # Add blocs in the pool
+        for a, b in self.blocs_mem_interval:
+            vm.vm_add_code_bloc(a, b + 1)
+
+    def __del_bloc_in_range(self, ad1, ad2):
+        """Find and remove jitted bloc in range [ad1, ad2].
+        Return the list of bloc removed.
+        @ad1: First address
+        @ad2: Last address
+        """
+
+        # Find concerned blocs
+        modified_blocs = set()
+        for b in self.lbl2bloc.values():
+            if not b.lines:
+                continue
+            if b.ad_max <= ad1 or b.ad_min >= ad2:
+                # Bloc not modified
+                pass
+            else:
+                # Modified blocs
+                modified_blocs.add(b)
+
+        # Generate interval to delete
+        del_interval = self.__blocs2memrange(modified_blocs)
+
+        # Remove interval from monitored interval list
+        self.blocs_mem_interval -= del_interval
+
+        # Remove modified blocs
+        for b in modified_blocs:
+            try:
+                for irbloc in b.irblocs:
+
+                    # Remove offset -> jitted bloc link
+                    if irbloc.label.offset in self.lbl2jitbloc:
+                        del(self.lbl2jitbloc[irbloc.label.offset])
+
+            except AttributeError:
+                # The bloc has never been translated in IR
+                if b.label.offset in self.lbl2jitbloc:
+                    del(self.lbl2jitbloc[b.label.offset])
+
+            # Remove label -> bloc link
+            del(self.lbl2bloc[b.label])
+
+        return modified_blocs
+
+    def updt_automod_code(self, vm, addr, size):
+        """Remove code jitted in range [addr, addr + size]
+        @vm: VmMngr instance
+        @addr: Address of modified code in sandbox
+        @size: Modification range size (in bits)
+        """
+
+        self.__del_bloc_in_range(addr, addr + size / 8)
+        self.__updt_jitcode_mem_range(vm)
+