about summary refs log tree commit diff stats
path: root/miasm2
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2')
-rw-r--r--miasm2/jitter/Jitgcc.c87
-rw-r--r--miasm2/jitter/jitcore_gcc.py136
-rw-r--r--miasm2/jitter/jitload.py67
3 files changed, 254 insertions, 36 deletions
diff --git a/miasm2/jitter/Jitgcc.c b/miasm2/jitter/Jitgcc.c
new file mode 100644
index 00000000..3e7225cb
--- /dev/null
+++ b/miasm2/jitter/Jitgcc.c
@@ -0,0 +1,87 @@
+#include <Python.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+typedef struct {
+	uint8_t is_local;
+	uint64_t address;
+} block_id;
+
+typedef int (*jitted_func)(block_id*, PyObject*);
+
+
+PyObject* gcc_exec_bloc(PyObject* self, PyObject* args)
+{
+	jitted_func func;
+	PyObject* jitcpu;
+	PyObject* func_py;
+	PyObject* lbl2ptr;
+	PyObject* breakpoints;
+	PyObject* retaddr = NULL;
+	int status;
+	block_id BlockDst;
+
+	if (!PyArg_ParseTuple(args, "OOOO", &retaddr, &jitcpu, &lbl2ptr, &breakpoints))
+		return NULL;
+
+	/* The loop will decref retaddr always once */
+	Py_INCREF(retaddr);
+
+	for (;;) {
+		// Init
+		BlockDst.is_local = 0;
+		BlockDst.address = 0;
+
+		// Get the expected jitted function address
+		func_py = PyDict_GetItem(lbl2ptr, retaddr);
+		if (func_py)
+			func = (jitted_func) PyInt_AsLong((PyObject*) func_py);
+		else {
+			if (BlockDst.is_local == 1) {
+				fprintf(stderr, "return on local label!\n");
+				exit(1);
+			}
+			// retaddr is not jitted yet
+			return retaddr;
+		}
+
+		// Execute it
+		status = func(&BlockDst, jitcpu);
+		Py_DECREF(retaddr);
+		retaddr = PyLong_FromUnsignedLongLong(BlockDst.address);
+
+		// Check exception
+		if (status)
+			return retaddr;
+
+		// Check breakpoint
+		if (PyDict_Contains(breakpoints, retaddr))
+			return retaddr;
+	}
+}
+
+
+
+static PyObject *GccError;
+
+
+static PyMethodDef GccMethods[] = {
+    {"gcc_exec_bloc",  gcc_exec_bloc, METH_VARARGS,
+     "gcc exec bloc"},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
+
+PyMODINIT_FUNC
+initJitgcc(void)
+{
+    PyObject *m;
+
+    m = Py_InitModule("Jitgcc", GccMethods);
+    if (m == NULL)
+	    return;
+
+    GccError = PyErr_NewException("gcc.error", NULL, NULL);
+    Py_INCREF(GccError);
+    PyModule_AddObject(m, "error", GccError);
+}
+
diff --git a/miasm2/jitter/jitcore_gcc.py b/miasm2/jitter/jitcore_gcc.py
new file mode 100644
index 00000000..cad64df3
--- /dev/null
+++ b/miasm2/jitter/jitcore_gcc.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+
+import os
+import tempfile
+import ctypes
+from distutils.sysconfig import get_python_inc
+from subprocess import check_call
+from hashlib import md5
+
+from miasm2.ir.ir2C import irblocs2C
+from miasm2.jitter import jitcore, Jitgcc
+from miasm2.core.utils import keydefaultdict
+
+
+def gen_core(arch, attrib):
+    lib_dir = os.path.dirname(os.path.realpath(__file__))
+
+    txt = ""
+    txt += '#include "%s/queue.h"\n' % lib_dir
+    txt += '#include "%s/vm_mngr.h"\n' % lib_dir
+    txt += '#include "%s/vm_mngr_py.h"\n' % lib_dir
+    txt += '#include "%s/JitCore.h"\n' % lib_dir
+    txt += '#include "%s/arch/JitCore_%s.h"\n' % (lib_dir, arch.name)
+    txt += r'''
+#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;}
+'''
+    return txt
+
+
+def gen_C_source(ir_arch, func_code):
+    c_source = ""
+    c_source += "\n".join(func_code)
+
+    c_source = gen_core(ir_arch.arch, ir_arch.attrib) + c_source
+    c_source = "#include <Python.h>\n" + c_source
+
+    return c_source
+
+
+class myresolver(object):
+
+    def __init__(self, offset):
+        self.offset = offset
+
+    def ret(self):
+        return "return PyLong_FromUnsignedLongLong(0x%X);" % self.offset
+
+
+class resolver(object):
+
+    def __init__(self):
+        self.resolvers = keydefaultdict(myresolver)
+
+    def get_resolver(self, offset):
+        return self.resolvers[offset]
+
+
+class JitCore_Gcc(jitcore.JitCore):
+
+    "JiT management, using GCC as backend"
+
+    def __init__(self, ir_arch, bs=None):
+        self.jitted_block_delete_cb = self.deleteCB
+        super(JitCore_Gcc, self).__init__(ir_arch, bs)
+        self.resolver = resolver()
+        self.gcc_states = {}
+        self.ir_arch = ir_arch
+        self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_gcc_cache")
+        try:
+            os.mkdir(self.tempdir, 0755)
+        except OSError:
+            pass
+        if not os.access(self.tempdir, os.R_OK | os.W_OK):
+            raise RuntimeError(
+                'Cannot access gcc cache directory %s ' % self.tempdir)
+        self.exec_wrapper = Jitgcc.gcc_exec_bloc
+        self.libs = None
+        self.include_files = None
+
+    def deleteCB(self, offset):
+        pass
+
+    def load(self):
+        lib_dir = os.path.dirname(os.path.realpath(__file__))
+        libs = [os.path.join(lib_dir, 'VmMngr.so'),
+                os.path.join(lib_dir,
+                             'arch/JitCore_%s.so' % (self.ir_arch.arch.name))]
+
+        include_files = [os.path.dirname(__file__),
+                         get_python_inc()]
+        self.include_files = include_files
+        self.libs = libs
+
+    def jit_gcc_compil(self, f_name, func_code):
+        func_hash = md5(func_code).hexdigest()
+        fname_out = os.path.join(self.tempdir, "%s.so" % func_hash)
+        if not os.access(fname_out, os.R_OK | os.X_OK):
+            # Create unique C file
+            fdesc, fname_in = tempfile.mkstemp(suffix=".c")
+            os.write(fdesc, func_code)
+            os.close(fdesc)
+
+            # Create unique SO file
+            _, fname_tmp = tempfile.mkstemp(suffix=".so")
+
+            inc_dir = ["-I%s" % inc for inc in self.include_files]
+            libs = ["%s" % lib for lib in self.libs]
+            args = ["gcc"] + ["-O3"] + [
+                "-shared", "-fPIC", fname_in, '-o', fname_tmp] + inc_dir + libs
+            check_call(args)
+            # Move temporary file to final file
+            os.rename(fname_tmp, fname_out)
+
+        lib = ctypes.cdll.LoadLibrary(fname_out)
+        func = getattr(lib, f_name)
+        addr = ctypes.cast(func, ctypes.c_void_p).value
+        return None, addr
+
+    def jitirblocs(self, label, irblocs):
+        f_name = "bloc_%s" % label.name
+        f_declaration = 'int %s(block_id * BlockDst, JitCpu* jitcpu)' % f_name
+        out = irblocs2C(self.ir_arch, self.resolver, label, irblocs,
+                        gen_exception_code=True,
+                        log_mn=self.log_mn,
+                        log_regs=self.log_regs)
+        out = [f_declaration + '{'] + out + ['}\n']
+        c_code = out
+
+        func_code = gen_C_source(self.ir_arch, c_code)
+
+        # open('tmp_%.4d.c'%self.jitcount, "w").write(func_code)
+        self.jitcount += 1
+        gcc_state, mcode = self.jit_gcc_compil(f_name, func_code)
+        self.lbl2jitbloc[label.offset] = mcode
+        self.gcc_states[label.offset] = gcc_state
diff --git a/miasm2/jitter/jitload.py b/miasm2/jitter/jitload.py
index 05a8575e..cc92b0cf 100644
--- a/miasm2/jitter/jitload.py
+++ b/miasm2/jitter/jitload.py
@@ -20,22 +20,6 @@ log_func = logging.getLogger('jit function call')
 log_func.addHandler(hnd)
 log_func.setLevel(logging.CRITICAL)
 
-
-try:
-    from miasm2.jitter.jitcore_tcc import JitCore_Tcc
-except ImportError:
-    log.error('cannot import jit tcc')
-
-try:
-    from miasm2.jitter.jitcore_llvm import JitCore_LLVM
-except ImportError:
-    log.error('cannot import jit llvm')
-
-try:
-    from miasm2.jitter.jitcore_python import JitCore_Python
-except ImportError:
-    log.error('cannot import jit python')
-
 try:
     from miasm2.jitter import VmMngr
 except ImportError:
@@ -189,18 +173,22 @@ class jitter:
         self.arch = ir_arch.arch
         self.attrib = ir_arch.attrib
         arch_name = ir_arch.arch.name  # (ir_arch.arch.name, ir_arch.attrib)
-        if arch_name == "x86":
-            from miasm2.jitter.arch import JitCore_x86 as jcore
-        elif arch_name == "arm":
-            from miasm2.jitter.arch import JitCore_arm as jcore
-        elif arch_name == "aarch64":
-            from miasm2.jitter.arch import JitCore_aarch64 as jcore
-        elif arch_name == "msp430":
-            from miasm2.jitter.arch import JitCore_msp430 as jcore
-        elif arch_name == "mips32":
-            from miasm2.jitter.arch import JitCore_mips32 as jcore
-        else:
-            raise ValueError("unsupported jit arch!")
+
+        try:
+            if arch_name == "x86":
+                from miasm2.jitter.arch import JitCore_x86 as jcore
+            elif arch_name == "arm":
+                from miasm2.jitter.arch import JitCore_arm as jcore
+            elif arch_name == "aarch64":
+                from miasm2.jitter.arch import JitCore_aarch64 as jcore
+            elif arch_name == "msp430":
+                from miasm2.jitter.arch import JitCore_msp430 as jcore
+            elif arch_name == "mips32":
+                from miasm2.jitter.arch import JitCore_mips32 as jcore
+            else:
+                raise ValueError("unknown jit arch: %s" % arch_name)
+        except ImportError:
+            raise RuntimeError('Unsupported jit arch: %s' % arch_name)
 
         self.vm = VmMngr.Vm()
         self.cpu = jcore.JitCpu()
@@ -211,14 +199,21 @@ class jitter:
         self.symbexec = EmulatedSymbExec(self.cpu, self.ir_arch, {})
         self.symbexec.reset_regs()
 
-        if jit_type == "tcc":
-            self.jit = JitCore_Tcc(self.ir_arch, self.bs)
-        elif jit_type == "llvm":
-            self.jit = JitCore_LLVM(self.ir_arch, self.bs)
-        elif jit_type == "python":
-            self.jit = JitCore_Python(self.ir_arch, self.bs)
-        else:
-            raise Exception("Unkown JiT Backend")
+        try:
+            if jit_type == "tcc":
+                from miasm2.jitter.jitcore_tcc import JitCore_Tcc as JitCore
+            elif jit_type == "llvm":
+                from miasm2.jitter.jitcore_llvm import JitCore_LLVM as JitCore
+            elif jit_type == "python":
+                from miasm2.jitter.jitcore_python import JitCore_Python as JitCore
+            elif jit_type == "gcc":
+                from miasm2.jitter.jitcore_gcc import JitCore_Gcc as JitCore
+            else:
+                raise ValueError("Unknown jitter %s" % jit_type)
+        except ImportError:
+            raise RuntimeError('Unsupported jitter: %s' % jit_type)
+
+        self.jit = JitCore(self.ir_arch, self.bs)
 
         self.cpu.init_regs()
         self.vm.init_memory_page_pool()