about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--miasm2/jitter/jitcore_python.py209
1 files changed, 140 insertions, 69 deletions
diff --git a/miasm2/jitter/jitcore_python.py b/miasm2/jitter/jitcore_python.py
index 0b1f5809..fdd5c2ae 100644
--- a/miasm2/jitter/jitcore_python.py
+++ b/miasm2/jitter/jitcore_python.py
@@ -1,5 +1,5 @@
 import miasm2.jitter.jitcore as jitcore
-import miasm2.expression.expression as m2_expr
+from miasm2.expression.expression import ExprInt, ExprLoc
 import miasm2.jitter.csts as csts
 from miasm2.expression.simplifications import expr_simp_explicit
 from miasm2.jitter.emulatedsymbexec import EmulatedSymbExec
@@ -36,12 +36,38 @@ class JitCore_Python(jitcore.JitCore):
         "Preload symbols according to current architecture"
         self.symbexec.reset_regs()
 
-    def jit_irblocks(self, loc_key, irblocks):
-        """Create a python function corresponding to an irblocks' group.
-        @loc_key: the loc_key of the irblocks
-        @irblocks: a group of irblocks
+    def arch_specific(self):
+        """Return arch specific information for the current architecture"""
+        arch = self.ir_arch.arch
+        has_delayslot = False
+        if arch.name == "mips32":
+            from miasm2.arch.mips32.jit import mipsCGen
+            cgen_class = mipsCGen
+            has_delayslot = True
+        elif arch.name == "arm":
+            from miasm2.arch.arm.jit import arm_CGen
+            cgen_class = arm_CGen
+        else:
+            from miasm2.jitter.codegen import CGen
+            cgen_class = CGen
+        return cgen_class(self.ir_arch), has_delayslot
+
+    def add_block(self, asmblock):
+        """Create a python function corresponding to an AsmBlock
+        @asmblock: AsmBlock
         """
 
+        # TODO: merge duplicate code with CGen, llvmconvert
+        codegen, has_delayslot = self.arch_specific()
+        irblocks_list = codegen.block2assignblks(asmblock)
+        instr_offsets = [line.offset for line in asmblock.lines]
+
+        loc_db = self.ir_arch.loc_db
+        local_loc_keys = []
+        for irblocks in irblocks_list:
+            for irblock in irblocks:
+                local_loc_keys.append(irblock.loc_key)
+
         def myfunc(cpu):
             """Execute the function according to cpu and vmmngr states
             @cpu: JitCpu instance
@@ -49,86 +75,131 @@ class JitCore_Python(jitcore.JitCore):
             # Get virtual memory handler
             vmmngr = cpu.vmmngr
 
-            # Keep current location in irblocks
-            cur_loc_key = loc_key
-
-            # Required to detect new instructions
-            offsets_jitted = set()
-
-            # Get exec engine
+            # Get execution engine (EmulatedSymbExec instance)
             exec_engine = self.symbexec
-            expr_simp = exec_engine.expr_simp
 
-            # For each irbloc inside irblocks
-            while True:
-                # Get the current bloc
-                for irb in irblocks:
-                    if irb.loc_key == cur_loc_key:
-                        break
+            # Refresh CPU values according to @cpu instance
+            exec_engine.update_engine_from_cpu()
 
-                else:
-                    raise RuntimeError("Irblocks must end with returning an "
-                                       "ExprInt instance")
-
-                # Refresh CPU values according to @cpu instance
-                exec_engine.update_engine_from_cpu()
-
-                # Execute current ir bloc
-                for assignblk in irb:
-                    instr = assignblk.instr
-                    # For each new instruction (in assembly)
-                    if instr is not None and instr.offset not in offsets_jitted:
-                        # Test exceptions
-                        vmmngr.check_invalid_code_blocs()
-                        vmmngr.check_memory_breakpoint()
-                        if vmmngr.get_exception():
-                            exec_engine.update_cpu_from_engine()
-                            return instr.offset
+            # Get initial loc_key
+            cur_loc_key = asmblock.loc_key
 
-                        offsets_jitted.add(instr.offset)
+            # Update PC helper
+            update_pc = lambda value: setattr(cpu, self.ir_arch.pc.name, value)
 
-                        # Log registers values
-                        if self.log_regs:
-                            exec_engine.update_cpu_from_engine()
-                            exec_engine.cpu.dump_gpregs_with_attrib(self.ir_arch.attrib)
+            while True:
+                # Retrieve the expected irblock
+                for instr, irblocks in zip(asmblock.lines, irblocks_list):
+                    for index, irblock in enumerate(irblocks):
+                        if irblock.loc_key == cur_loc_key:
+                            break
+                    else:
+                        continue
+                    break
+                else:
+                    raise RuntimeError("Unable to find the block for %r" % cur_loc_key)
+
+                instr_attrib, irblocks_attributes = codegen.get_attributes(
+                    instr, irblocks, self.log_mn, self.log_regs
+                )
+                irblock_attributes = irblocks_attributes[index]
+
+                # Do IRBlock
+                new_irblock = self.ir_arch.irbloc_fix_regs_for_mode(
+                    irblock, self.ir_arch.attrib
+                )
+                if index == 0:
+                    # Pre code
+                    if instr_attrib.log_mn:
+                        print "%.8X %s" % (
+                            instr_attrib.instr.offset,
+                            instr_attrib.instr.to_string(loc_db)
+                        )
+
+                # Exec IRBlock
+                instr = instr_attrib.instr
+
+                for index, assignblk in enumerate(irblock):
+                    attributes = irblock_attributes[index]
 
-                        # Log instruction
-                        if self.log_mn:
-                            print "%08x %s" % (instr.offset, instr)
+                    # Eval current instruction (in IR)
+                    exec_engine.eval_updt_assignblk(assignblk)
 
-                        # Check for exception
-                        if (vmmngr.get_exception() != 0 or
-                            cpu.get_exception() != 0):
-                            exec_engine.update_cpu_from_engine()
+                    # Check memory access / write exception
+                    # TODO: insert a check between memory reads and writes
+                    if attributes.mem_read or attributes.mem_write:
+                        # Restricted exception
+                        flag = ~csts.EXCEPT_CODE_AUTOMOD & csts.EXCEPT_DO_NOT_UPDATE_PC
+                        if (vmmngr.get_exception() & flag != 0):
+                            # Do not update registers
+                            update_pc(instr.offset)
                             return instr.offset
 
-                    # Eval current instruction (in IR)
-                    exec_engine.eval_updt_assignblk(assignblk)
-                    # Check for exceptions which do not update PC
+                    # Update registers values
                     exec_engine.update_cpu_from_engine()
-                    if (vmmngr.get_exception() & csts.EXCEPT_DO_NOT_UPDATE_PC != 0 or
-                        cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP):
-                        return instr.offset
-
-                vmmngr.check_invalid_code_blocs()
-                vmmngr.check_memory_breakpoint()
 
-                # Get next bloc address
-                ad = expr_simp(exec_engine.eval_expr(self.ir_arch.IRDst))
+                    # Check post assignblk exception flags
+                    if attributes.set_exception:
+                        # Restricted exception
+                        if cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP:
+                            # Update PC
+                            update_pc(instr.offset)
+                            return instr.offset
 
-                # Updates @cpu instance according to new CPU values
-                exec_engine.update_cpu_from_engine()
+                dst = exec_engine.eval_expr(self.ir_arch.IRDst)
+                if dst.is_int():
+                    loc_key = loc_db.get_or_create_offset_location(int(dst))
+                    dst = ExprLoc(loc_key, dst.size)
+
+                assert dst.is_loc()
+                loc_key = dst.loc_key
+                offset = loc_db.get_location_offset(loc_key)
+                if offset is None:
+                    # Avoid checks on generated label
+                    cur_loc_key = loc_key
+                    continue
+
+                if instr_attrib.log_regs:
+                    update_pc(offset)
+                    cpu.dump_gpregs_with_attrib(self.ir_arch.attrib)
+
+                # Post-instr checks
+                if instr_attrib.mem_read | instr_attrib.mem_write:
+                    vmmngr.check_memory_breakpoint()
+                    vmmngr.check_invalid_code_blocs()
+                    if vmmngr.get_exception():
+                        update_pc(offset)
+                        return offset
+
+                if instr_attrib.set_exception:
+                    if cpu.get_exception():
+                        update_pc(offset)
+                        return offset
+
+                if instr_attrib.mem_read | instr_attrib.mem_write:
+                    vmmngr.reset_memory_access()
 
                 # Manage resulting address
-                if isinstance(ad, m2_expr.ExprInt):
-                    return ad.arg.arg
-                elif isinstance(ad, m2_expr.ExprLoc):
-                    cur_loc_key = ad.loc_key
-                else:
-                    raise NotImplementedError("Type not handled: %s" % ad)
+                if (loc_key in local_loc_keys and
+                    offset > instr.offset):
+                    # Forward local jump
+                    # Note: a backward local jump has to be promoted to extern,
+                    # for max_exec_per_call support
+                    cur_loc_key = loc_key
+                    continue
+
+                # Delay slot
+                if has_delayslot:
+                    delay_slot_set = exec_engine.eval_expr(codegen.delay_slot_set)
+                    if delay_slot_set.is_int() and int(delay_slot_set) != 0:
+                        return int(exec_engine.eval_expr(codegen.delay_slot_dst))
+
+                # Extern of asmblock, must have an offset
+                assert offset is not None
+                return offset
 
         # Associate myfunc with current loc_key
-        offset = self.ir_arch.loc_db.get_location_offset(loc_key)
+        offset = loc_db.get_location_offset(asmblock.loc_key)
         assert offset is not None
         self.offset_to_jitted_func[offset] = myfunc