diff options
Diffstat (limited to 'src/miasm/jitter')
47 files changed, 16738 insertions, 0 deletions
diff --git a/src/miasm/jitter/JitCore.c b/src/miasm/jitter/JitCore.c new file mode 100644 index 00000000..dfead5a8 --- /dev/null +++ b/src/miasm/jitter/JitCore.c @@ -0,0 +1,247 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <limits.h> +#include <inttypes.h> +#include "compat_py23.h" +#include "queue.h" +#include "vm_mngr.h" +#include "bn.h" +#include "vm_mngr_py.h" +#include "JitCore.h" + + +void JitCpu_dealloc(JitCpu* self) +{ + Py_TYPE(self)->tp_free((PyObject*)self); +} + + +PyObject * JitCpu_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + JitCpu *self; + + self = (JitCpu *)type->tp_alloc(type, 0); + return (PyObject *)self; +} + +PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure) +{ + if (self->pyvm) { + Py_INCREF(self->pyvm); + return (PyObject*)self->pyvm; + } + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * JitCpu_set_vmmngr(JitCpu *self, PyObject *value, void *closure) +{ + self->pyvm = (VmMngr*)value; + return 0; +} + + + +PyObject * JitCpu_get_vmcpu(JitCpu *self, void *closure) +{ + PyObject * ret; + uint64_t addr; + addr = (uint64_t) self->cpu; + ret = PyLong_FromUnsignedLongLong(addr); + return ret; +} + +PyObject * JitCpu_set_vmcpu(JitCpu *self, PyObject *value, void *closure) +{ + fprintf(stderr, "Set vmcpu not supported yet\n"); + exit(-1); +} + + + +PyObject * JitCpu_get_jitter(JitCpu *self, void *closure) +{ + if (self->jitter) { + Py_INCREF(self->jitter); + return self->jitter; + } + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * JitCpu_set_jitter(JitCpu *self, PyObject *value, void *closure) +{ + self->jitter = value; + return 0; +} + +uint8_t MEM_LOOKUP_08(JitCpu* jitcpu, uint64_t addr) +{ + return vm_MEM_LOOKUP_08(&(jitcpu->pyvm->vm_mngr), addr); +} + +uint16_t MEM_LOOKUP_16(JitCpu* jitcpu, uint64_t addr) +{ + return vm_MEM_LOOKUP_16(&(jitcpu->pyvm->vm_mngr), addr); +} + +uint32_t MEM_LOOKUP_32(JitCpu* jitcpu, uint64_t addr) +{ + return vm_MEM_LOOKUP_32(&(jitcpu->pyvm->vm_mngr), addr); +} + +uint64_t MEM_LOOKUP_64(JitCpu* jitcpu, uint64_t addr) +{ + return vm_MEM_LOOKUP_64(&(jitcpu->pyvm->vm_mngr), addr); +} + +bn_t MEM_LOOKUP_BN_BN(JitCpu* jitcpu, int size, bn_t addr) +{ + uint64_t ptr; + int i; + uint8_t tmp; + bn_t val = bignum_from_int(0); + + ptr = bignum_to_uint64(addr); + + + for (i=0; i < size; i += 8) { + tmp = vm_MEM_LOOKUP_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr); + ptr += 1; + val = bignum_or(val, bignum_lshift(bignum_from_int(tmp), i)); + } + + return val; +} + + +uint64_t MEM_LOOKUP_BN_INT(JitCpu* jitcpu, int size, bn_t addr) +{ + uint64_t ptr; + uint64_t val = 0; + + ptr = bignum_to_uint64(addr); + + switch (size) { + case 8: + val = vm_MEM_LOOKUP_08(&(jitcpu->pyvm->vm_mngr), ptr); + break; + case 16: + val = vm_MEM_LOOKUP_16(&(jitcpu->pyvm->vm_mngr), ptr); + break; + case 32: + val = vm_MEM_LOOKUP_32(&(jitcpu->pyvm->vm_mngr), ptr); + break; + case 64: + val = vm_MEM_LOOKUP_64(&(jitcpu->pyvm->vm_mngr), ptr); + break; + default: + fprintf(stderr, "Error: bad READ size %d\n", size); + exit(-1); + break; + } + + return val; +} + + + +bn_t MEM_LOOKUP_INT_BN(JitCpu* jitcpu, int size, uint64_t addr) +{ + int i; + uint8_t tmp; + bn_t val = bignum_from_int(0); + + for (i=0; i < size; i += 8) { + tmp = vm_MEM_LOOKUP_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr); + addr += 1; + val = bignum_or(val, bignum_lshift(bignum_from_int(tmp), i)); + } + + return val; +} + + +void MEM_LOOKUP_INT_BN_TO_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr) +{ + bn_t ret; + + if (size % 8) { + fprintf(stderr, "Bad size %d\n", size); + exit(-1); + } + + ret = MEM_LOOKUP_INT_BN(jitcpu, size, addr); + memcpy(ptr, (char*)&ret, size / 8); +} + + +void MEM_WRITE_BN_BN(JitCpu* jitcpu, int size, bn_t addr, bn_t src) +{ + uint64_t ptr; + int val; + int i; + + ptr = bignum_to_uint64(addr); + for (i=0; i < size; i += 8) { + val = bignum_to_uint64(src) & 0xFF; + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, val); + ptr += 1; + src = bignum_rshift(src, 8); + } +} + + +void MEM_WRITE_BN_INT(JitCpu* jitcpu, int size, bn_t addr, uint64_t src) +{ + uint64_t ptr; + ptr = bignum_to_uint64(addr); + + switch (size) { + case 8: + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned char)src); + break; + case 16: + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned short)src); + break; + case 32: + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, (unsigned int)src); + break; + case 64: + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, ptr, src); + break; + default: + fprintf(stderr, "Error: bad write size %d\n", size); + exit(-1); + break; + } +} + +void MEM_WRITE_INT_BN(JitCpu* jitcpu, int size, uint64_t addr, bn_t src) +{ + int val; + int i; + + for (i=0; i < size; i += 8) { + val = bignum_to_uint64(src) & 0xFF; + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, val); + addr += 1; + src = bignum_rshift(src, 8); + } +} + + +void MEM_WRITE_INT_BN_FROM_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr) +{ + bn_t val; + + if (size % 8) { + fprintf(stderr, "Bad size %d\n", size); + exit(-1); + } + + val = bignum_from_int(0); + memcpy(&val, ptr, size / 8); + MEM_WRITE_INT_BN(jitcpu, size, addr, val); +} diff --git a/src/miasm/jitter/JitCore.h b/src/miasm/jitter/JitCore.h new file mode 100644 index 00000000..ff6ff159 --- /dev/null +++ b/src/miasm/jitter/JitCore.h @@ -0,0 +1,242 @@ +#ifndef JITCORE_H +#define JITCORE_H + +#if _WIN32 +#define _MIASM_EXPORT __declspec(dllexport) + +#ifndef SSIZE_MAX +#ifdef _WIN64 +#define SSIZE_MAX _I64_MAX +#else +#define SSIZE_MAX INT_MAX +#endif +#endif + +#else +#define _MIASM_EXPORT +#endif + +#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;} +#define RAISE_ret0(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return 0;} + + +#if PY_MAJOR_VERSION >= 3 +#define getset_reg_bn(regname, size) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + bn_t bn; \ + PyObject* py_long; \ + bn = (self->cpu)->regname; \ + bn = bignum_mask(bn, (size)); \ + py_long = bn_to_PyLong(bn); \ + return py_long; \ + } \ + \ + static PyObject *JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + bn_t bn; \ + PyObject* py_long = value; \ + if (PyLong_Check(py_long)){ \ + Py_INCREF(py_long); \ + } else { \ + RAISE(PyExc_TypeError,"arg must be int"); \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + (self->cpu)->regname = bignum_mask(bn, (size)); \ + return 0; \ + } + + +#else +#define getset_reg_bn(regname, size) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + bn_t bn; \ + PyObject* py_long; \ + bn = (self->cpu)->regname; \ + bn = bignum_mask(bn, (size)); \ + py_long = bn_to_PyLong(bn); \ + return py_long; \ + } \ + \ + static PyObject *JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + bn_t bn; \ + PyObject* py_long = value; \ + uint64_t tmp; \ + \ + if (PyInt_Check(py_long)){ \ + tmp = (uint64_t)PyInt_AsLong(py_long); \ + py_long = PyLong_FromLong((long)tmp); \ + } else if (PyLong_Check(py_long)){ \ + Py_INCREF(py_long); \ + } \ + else{ \ + RAISE(PyExc_TypeError,"arg must be int"); \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + self->cpu->regname = bignum_mask(bn, (size)); \ + return 0; \ + } +#endif + + + + + + + + + + + +#define getset_reg_u64(regname) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong(self->cpu->regname); \ + } \ + static int JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint64_t val; \ + PyGetInt_uint64_t_retneg(value, val); \ + self->cpu->regname = val; \ + return 0; \ + } + +#define getset_reg_u32(regname) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong(self->cpu->regname); \ + } \ + static int JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint32_t val; \ + PyGetInt_uint32_t_retneg(value, val); \ + self->cpu->regname = val; \ + return 0; \ + } + + +#define getset_reg_u16(regname) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong(self->cpu->regname); \ + } \ + static int JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint16_t val; \ + PyGetInt_uint16_t_retneg(value, val); \ + self->cpu->regname = val; \ + return 0; \ + } + + +#define getset_reg_u8(regname) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong(self->cpu->regname); \ + } \ + static int JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint8_t val; \ + PyGetInt_uint8_t_retneg(value, val); \ + self->cpu->regname = val; \ + return 0; \ + } + + +#define get_reg(reg) do { \ + o = PyLong_FromUnsignedLongLong((uint64_t)self->cpu->reg); \ + PyDict_SetItemString(dict, #reg, o); \ + Py_DECREF(o); \ + } while(0); + + +#define get_reg_bn(reg, size) do { \ + bn_t bn; \ + PyObject* py_long; \ + bn = self->cpu->reg; \ + bn = bignum_mask(bn, size); \ + py_long = bn_to_PyLong(bn); \ + PyDict_SetItemString(dict, #reg, py_long); \ + Py_DECREF(py_long); \ + } while(0); + + +#define get_reg_off(reg) do { \ + o = PyLong_FromUnsignedLongLong((uint64_t)offsetof(struct vm_cpu, reg)); \ + PyDict_SetItemString(dict, #reg, o); \ + Py_DECREF(o); \ + } while(0); + + + + +typedef struct { + uint8_t is_local; + uint64_t address; +} block_id; + +struct vm_cpu; + +typedef struct { + PyObject_HEAD + VmMngr *pyvm; + PyObject *jitter; + struct vm_cpu *cpu; +} JitCpu; + + +typedef struct _reg_dict{ + char* name; + size_t offset; + size_t size; +} reg_dict; + + + +void JitCpu_dealloc(JitCpu* self); +PyObject * JitCpu_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +PyObject * JitCpu_get_vmmngr(JitCpu *self, void *closure); +PyObject * JitCpu_set_vmmngr(JitCpu *self, PyObject *value, void *closure); +PyObject * JitCpu_get_vmcpu(JitCpu *self, void *closure); +PyObject * JitCpu_set_vmcpu(JitCpu *self, PyObject *value, void *closure); +PyObject * JitCpu_get_jitter(JitCpu *self, void *closure); +PyObject * JitCpu_set_jitter(JitCpu *self, PyObject *value, void *closure); +void Resolve_dst(block_id* BlockDst, uint64_t addr, uint64_t is_local); + +#define Resolve_dst(b, arg_addr, arg_is_local) do {(b)->address = (arg_addr); (b)->is_local = (arg_is_local);} while(0) + + + +_MIASM_EXPORT uint8_t MEM_LOOKUP_08(JitCpu* jitcpu, uint64_t addr); +_MIASM_EXPORT uint16_t MEM_LOOKUP_16(JitCpu* jitcpu, uint64_t addr); +_MIASM_EXPORT uint32_t MEM_LOOKUP_32(JitCpu* jitcpu, uint64_t addr); +_MIASM_EXPORT uint64_t MEM_LOOKUP_64(JitCpu* jitcpu, uint64_t addr); + +_MIASM_EXPORT bn_t MEM_LOOKUP_BN_BN(JitCpu* jitcpu, int size, bn_t addr); +_MIASM_EXPORT bn_t MEM_LOOKUP_INT_BN(JitCpu* jitcpu, int size, uint64_t addr); + +_MIASM_EXPORT uint64_t MEM_LOOKUP_BN_INT(JitCpu* jitcpu, int size, bn_t addr); + +_MIASM_EXPORT void MEM_WRITE_BN_BN(JitCpu* jitcpu, int size, bn_t addr, bn_t src); +_MIASM_EXPORT void MEM_WRITE_BN_INT(JitCpu* jitcpu, int size, bn_t addr, uint64_t src); +_MIASM_EXPORT void MEM_WRITE_INT_BN(JitCpu* jitcpu, int size, uint64_t addr, bn_t src); + + +_MIASM_EXPORT void MEM_LOOKUP_INT_BN_TO_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr); +_MIASM_EXPORT void MEM_WRITE_INT_BN_FROM_PTR(JitCpu* jitcpu, int size, uint64_t addr, char* ptr); + + + +#define VM_exception_flag (jitcpu->pyvm->vm_mngr.exception_flags) +#define CPU_exception_flag (((struct vm_cpu*)jitcpu->cpu)->exception_flags) +#define CPU_exception_flag_at_instr ((CPU_exception_flag) && ((CPU_exception_flag) > EXCEPT_NUM_UPDT_EIP)) +#define JIT_RET_EXCEPTION 1 +#define JIT_RET_NO_EXCEPTION 0 + +#endif diff --git a/src/miasm/jitter/Jitgcc.c b/src/miasm/jitter/Jitgcc.c new file mode 100644 index 00000000..9dc7b2fd --- /dev/null +++ b/src/miasm/jitter/Jitgcc.c @@ -0,0 +1,100 @@ +#include <Python.h> +#include <inttypes.h> +#include <stdint.h> +#include "compat_py23.h" + +typedef struct { + uint8_t is_local; + uint64_t address; +} block_id; + +typedef int (*jitted_func)(block_id*, PyObject*); + + +PyObject* gcc_exec_block(PyObject* self, PyObject* args) +{ + jitted_func func; + PyObject* jitcpu; + PyObject* func_py; + PyObject* lbl2ptr; + PyObject* stop_offsets; + PyObject* retaddr = NULL; + int status; + block_id BlockDst; + uint64_t max_exec_per_call = 0; + uint64_t cpt; + int do_cpt; + + + if (!PyArg_ParseTuple(args, "OOOO|K", + &retaddr, &jitcpu, &lbl2ptr, &stop_offsets, + &max_exec_per_call)) + return NULL; + + /* The loop will decref retaddr always once */ + Py_INCREF(retaddr); + + if (max_exec_per_call == 0) { + do_cpt = 0; + cpt = 1; + } else { + do_cpt = 1; + cpt = max_exec_per_call; + } + + + + for (;;) { + if (cpt == 0) + return retaddr; + if (do_cpt) + cpt --; + // 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) PyLong_AsVoidPtr((PyObject*) func_py); + else { + if (BlockDst.is_local == 1) { + fprintf(stderr, "return on local label!\n"); + exit(EXIT_FAILURE); + } + // 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 stop offsets + if (PySet_Contains(stop_offsets, retaddr)) + return retaddr; + } +} + + + +static PyMethodDef GccMethods[] = { + {"gcc_exec_block", gcc_exec_block, METH_VARARGS, + "gcc exec block"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + + +MOD_INIT(Jitgcc) +{ + PyObject *module = NULL; + + MOD_DEF(module, "Jitgcc", "gcc module", GccMethods); + + RET_MODULE; +} diff --git a/src/miasm/jitter/Jitllvm.c b/src/miasm/jitter/Jitllvm.c new file mode 100644 index 00000000..3420c254 --- /dev/null +++ b/src/miasm/jitter/Jitllvm.c @@ -0,0 +1,96 @@ +#include <Python.h> + +#include <inttypes.h> + +#include <stdint.h> +#include "compat_py23.h" +#include "queue.h" +#include "vm_mngr.h" +#include "bn.h" +#include "vm_mngr_py.h" +#include "JitCore.h" +// Needed to get the JitCpu.cpu offset, arch independent +#include "arch/JitCore_x86.h" + +PyObject* llvm_exec_block(PyObject* self, PyObject* args) +{ + uint64_t (*func)(void*, void*, void*, uint8_t*); + struct vm_cpu* cpu; + vm_mngr_t* vm; + uint64_t ret; + JitCpu* jitcpu; + uint8_t status; + PyObject* func_py; + PyObject* lbl2ptr; + PyObject* stop_offsets; + PyObject* retaddr = NULL; + uint64_t max_exec_per_call = 0; + uint64_t cpt; + int do_cpt; + + if (!PyArg_ParseTuple(args, "OOOO|K", + &retaddr, &jitcpu, &lbl2ptr, &stop_offsets, + &max_exec_per_call)) + return NULL; + + cpu = jitcpu->cpu; + vm = &(jitcpu->pyvm->vm_mngr); + /* The loop will decref retaddr always once */ + Py_INCREF(retaddr); + + if (max_exec_per_call == 0) { + do_cpt = 0; + cpt = 1; + } else { + do_cpt = 1; + cpt = max_exec_per_call; + } + + for (;;) { + // Handle cpt + if (cpt == 0) + return retaddr; + if (do_cpt) + cpt --; + + // Get the expected jitted function address + func_py = PyDict_GetItem(lbl2ptr, retaddr); + if (func_py) + func = PyLong_AsVoidPtr((PyObject*) func_py); + else + // retaddr is not jitted yet + return retaddr; + + // Execute it + ret = func((void*) jitcpu, (void*)(intptr_t) cpu, (void*)(intptr_t) vm, &status); + Py_DECREF(retaddr); + retaddr = PyLong_FromUnsignedLongLong(ret); + + // Check exception + if (status) + return retaddr; + + // Check stop offsets + if (PySet_Contains(stop_offsets, retaddr)) + return retaddr; + } +} + + +static PyMethodDef LLVMMethods[] = { + {"llvm_exec_block", llvm_exec_block, METH_VARARGS, + "llvm exec block"}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + + + +MOD_INIT(Jitllvm) +{ + PyObject *module = NULL; + + MOD_DEF(module, "Jitllvm", "llvm module", LLVMMethods); + + RET_MODULE; +} diff --git a/src/miasm/jitter/__init__.py b/src/miasm/jitter/__init__.py new file mode 100644 index 00000000..460e327d --- /dev/null +++ b/src/miasm/jitter/__init__.py @@ -0,0 +1 @@ +"JustInTime compilation feature" diff --git a/src/miasm/jitter/arch/JitCore_aarch64.c b/src/miasm/jitter/arch/JitCore_aarch64.c new file mode 100644 index 00000000..7961f3cc --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_aarch64.c @@ -0,0 +1,519 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_aarch64.h" + + + +reg_dict gpreg_dict[] = { + {.name = "X0", .offset = offsetof(struct vm_cpu, X0), .size = 64}, + {.name = "X1", .offset = offsetof(struct vm_cpu, X1), .size = 64}, + {.name = "X2", .offset = offsetof(struct vm_cpu, X2), .size = 64}, + {.name = "X3", .offset = offsetof(struct vm_cpu, X3), .size = 64}, + {.name = "X4", .offset = offsetof(struct vm_cpu, X4), .size = 64}, + {.name = "X5", .offset = offsetof(struct vm_cpu, X5), .size = 64}, + {.name = "X6", .offset = offsetof(struct vm_cpu, X6), .size = 64}, + {.name = "X7", .offset = offsetof(struct vm_cpu, X7), .size = 64}, + {.name = "X8", .offset = offsetof(struct vm_cpu, X8), .size = 64}, + {.name = "X9", .offset = offsetof(struct vm_cpu, X9), .size = 64}, + {.name = "X10", .offset = offsetof(struct vm_cpu, X10), .size = 64}, + {.name = "X11", .offset = offsetof(struct vm_cpu, X11), .size = 64}, + {.name = "X12", .offset = offsetof(struct vm_cpu, X12), .size = 64}, + {.name = "X13", .offset = offsetof(struct vm_cpu, X13), .size = 64}, + {.name = "X14", .offset = offsetof(struct vm_cpu, X14), .size = 64}, + {.name = "X15", .offset = offsetof(struct vm_cpu, X15), .size = 64}, + {.name = "X16", .offset = offsetof(struct vm_cpu, X16), .size = 64}, + {.name = "X17", .offset = offsetof(struct vm_cpu, X17), .size = 64}, + {.name = "X18", .offset = offsetof(struct vm_cpu, X18), .size = 64}, + {.name = "X19", .offset = offsetof(struct vm_cpu, X19), .size = 64}, + {.name = "X20", .offset = offsetof(struct vm_cpu, X20), .size = 64}, + {.name = "X21", .offset = offsetof(struct vm_cpu, X21), .size = 64}, + {.name = "X22", .offset = offsetof(struct vm_cpu, X22), .size = 64}, + {.name = "X23", .offset = offsetof(struct vm_cpu, X23), .size = 64}, + {.name = "X24", .offset = offsetof(struct vm_cpu, X24), .size = 64}, + {.name = "X25", .offset = offsetof(struct vm_cpu, X25), .size = 64}, + {.name = "X26", .offset = offsetof(struct vm_cpu, X26), .size = 64}, + {.name = "X27", .offset = offsetof(struct vm_cpu, X27), .size = 64}, + {.name = "X28", .offset = offsetof(struct vm_cpu, X28), .size = 64}, + {.name = "X29", .offset = offsetof(struct vm_cpu, X29), .size = 64}, + {.name = "LR", .offset = offsetof(struct vm_cpu, LR), .size = 64}, + + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 64}, + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 64}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8}, + {.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, + +}; + +/************************** JitCpu object **************************/ + + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(X0); + get_reg(X1); + get_reg(X2); + get_reg(X3); + get_reg(X4); + get_reg(X5); + get_reg(X6); + get_reg(X7); + get_reg(X8); + get_reg(X9); + get_reg(X10); + get_reg(X11); + get_reg(X12); + get_reg(X13); + get_reg(X14); + get_reg(X15); + get_reg(X16); + get_reg(X17); + get_reg(X18); + get_reg(X19); + get_reg(X20); + get_reg(X21); + get_reg(X22); + get_reg(X23); + get_reg(X24); + get_reg(X25); + get_reg(X26); + get_reg(X27); + get_reg(X28); + get_reg(X29); + get_reg(LR); + get_reg(SP); + get_reg(PC); + + get_reg(zf); + get_reg(nf); + get_reg(of); + get_reg(cf); + + return dict; +} + + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val32; + uint64_t val64; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + found = 1; + switch (gpreg_dict[i].size) { + default: + RAISE(PyExc_TypeError, "Unsupported size"); + break; + case 32: + PyGetInt_uint32_t(d_value, val32); + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val32; + break; + case 64: + PyGetInt_uint64_t(d_value, val64); + *((uint64_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val64; + break; + } + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("X0 %.16"PRIX64" X1 %.16"PRIX64" X2 %.16"PRIX64" X3 %.16"PRIX64" "\ + "X4 %.16"PRIX64" X5 %.16"PRIX64" X6 %.16"PRIX64" X7 %.16"PRIX64"\n", + vmcpu->X0, vmcpu->X1, vmcpu->X2, vmcpu->X3, vmcpu->X4, vmcpu->X5, vmcpu->X6, vmcpu->X7); + printf("X8 %.16"PRIX64" X9 %.16"PRIX64" X10 %.16"PRIX64" X11 %.16"PRIX64" "\ + "X12 %.16"PRIX64" X13 %.16"PRIX64" X14 %.16"PRIX64" X15 %.16"PRIX64"\n", + vmcpu->X8, vmcpu->X9, vmcpu->X10, vmcpu->X11, + vmcpu->X12, vmcpu->X13, vmcpu->X14, vmcpu->X15); + printf("X16 %.16"PRIX64" X17 %.16"PRIX64" X18 %.16"PRIX64" X19 %.16"PRIX64" "\ + "X20 %.16"PRIX64" X21 %.16"PRIX64" X22 %.16"PRIX64" X23 %.16"PRIX64"\n", + vmcpu->X16, vmcpu->X17, vmcpu->X18, vmcpu->X19, + vmcpu->X20, vmcpu->X21, vmcpu->X22, vmcpu->X23); + printf("X24 %.16"PRIX64" X25 %.16"PRIX64" X26 %.16"PRIX64" X27 %.16"PRIX64" "\ + "X28 %.16"PRIX64" X29 %.16"PRIX64" LR %.16"PRIX64"\n", + vmcpu->X24, vmcpu->X25, vmcpu->X26, vmcpu->X27, + vmcpu->X28, vmcpu->X29, vmcpu->LR); + + + printf("SP %.16"PRIX64" PC %.16"PRIX64" "\ + "zf %"PRIX32" nf %"PRIX32" of %"PRIX32" cf %"PRIX32"\n", + vmcpu->SP, vmcpu->PC, + vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + + + +getset_reg_u64(X0); +getset_reg_u64(X1); +getset_reg_u64(X2); +getset_reg_u64(X3); +getset_reg_u64(X4); +getset_reg_u64(X5); +getset_reg_u64(X6); +getset_reg_u64(X7); +getset_reg_u64(X8); +getset_reg_u64(X9); +getset_reg_u64(X10); +getset_reg_u64(X11); +getset_reg_u64(X12); +getset_reg_u64(X13); +getset_reg_u64(X14); +getset_reg_u64(X15); +getset_reg_u64(X16); +getset_reg_u64(X17); +getset_reg_u64(X18); +getset_reg_u64(X19); +getset_reg_u64(X20); +getset_reg_u64(X21); +getset_reg_u64(X22); +getset_reg_u64(X23); +getset_reg_u64(X24); +getset_reg_u64(X25); +getset_reg_u64(X26); +getset_reg_u64(X27); +getset_reg_u64(X28); +getset_reg_u64(X29); +getset_reg_u64(LR); +getset_reg_u64(SP); +getset_reg_u64(PC); + +getset_reg_u32(zf); +getset_reg_u32(nf); +getset_reg_u32(of); +getset_reg_u32(cf); + + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + + get_reg_off(X0); + get_reg_off(X1); + get_reg_off(X2); + get_reg_off(X3); + get_reg_off(X4); + get_reg_off(X5); + get_reg_off(X6); + get_reg_off(X7); + get_reg_off(X8); + get_reg_off(X9); + get_reg_off(X10); + get_reg_off(X11); + get_reg_off(X12); + get_reg_off(X13); + get_reg_off(X14); + get_reg_off(X15); + get_reg_off(X16); + get_reg_off(X17); + get_reg_off(X18); + get_reg_off(X19); + get_reg_off(X20); + get_reg_off(X21); + get_reg_off(X22); + get_reg_off(X23); + get_reg_off(X24); + get_reg_off(X25); + get_reg_off(X26); + get_reg_off(X27); + get_reg_off(X28); + get_reg_off(X29); + get_reg_off(LR); + get_reg_off(SP); + get_reg_off(PC); + + /* eflag */ + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(of); + get_reg_off(cf); + + return dict; +} + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + + {"X0" , (getter)JitCpu_get_X0 , (setter)JitCpu_set_X0 , "X0" , NULL}, + {"X1" , (getter)JitCpu_get_X1 , (setter)JitCpu_set_X1 , "X1" , NULL}, + {"X2" , (getter)JitCpu_get_X2 , (setter)JitCpu_set_X2 , "X2" , NULL}, + {"X3" , (getter)JitCpu_get_X3 , (setter)JitCpu_set_X3 , "X3" , NULL}, + {"X4" , (getter)JitCpu_get_X4 , (setter)JitCpu_set_X4 , "X4" , NULL}, + {"X5" , (getter)JitCpu_get_X5 , (setter)JitCpu_set_X5 , "X5" , NULL}, + {"X6" , (getter)JitCpu_get_X6 , (setter)JitCpu_set_X6 , "X6" , NULL}, + {"X7" , (getter)JitCpu_get_X7 , (setter)JitCpu_set_X7 , "X7" , NULL}, + {"X8" , (getter)JitCpu_get_X8 , (setter)JitCpu_set_X8 , "X8" , NULL}, + {"X9" , (getter)JitCpu_get_X9 , (setter)JitCpu_set_X9 , "X9" , NULL}, + + {"X10" , (getter)JitCpu_get_X10 , (setter)JitCpu_set_X10 , "X10" , NULL}, + {"X11" , (getter)JitCpu_get_X11 , (setter)JitCpu_set_X11 , "X11" , NULL}, + {"X12" , (getter)JitCpu_get_X12 , (setter)JitCpu_set_X12 , "X12" , NULL}, + {"X13" , (getter)JitCpu_get_X13 , (setter)JitCpu_set_X13 , "X13" , NULL}, + {"X14" , (getter)JitCpu_get_X14 , (setter)JitCpu_set_X14 , "X14" , NULL}, + {"X15" , (getter)JitCpu_get_X15 , (setter)JitCpu_set_X15 , "X15" , NULL}, + {"X16" , (getter)JitCpu_get_X16 , (setter)JitCpu_set_X16 , "X16" , NULL}, + {"X17" , (getter)JitCpu_get_X17 , (setter)JitCpu_set_X17 , "X17" , NULL}, + {"X18" , (getter)JitCpu_get_X18 , (setter)JitCpu_set_X18 , "X18" , NULL}, + {"X19" , (getter)JitCpu_get_X19 , (setter)JitCpu_set_X19 , "X19" , NULL}, + + {"X20" , (getter)JitCpu_get_X20 , (setter)JitCpu_set_X20 , "X20" , NULL}, + {"X21" , (getter)JitCpu_get_X21 , (setter)JitCpu_set_X21 , "X21" , NULL}, + {"X22" , (getter)JitCpu_get_X22 , (setter)JitCpu_set_X22 , "X22" , NULL}, + {"X23" , (getter)JitCpu_get_X23 , (setter)JitCpu_set_X23 , "X23" , NULL}, + {"X24" , (getter)JitCpu_get_X24 , (setter)JitCpu_set_X24 , "X24" , NULL}, + {"X25" , (getter)JitCpu_get_X25 , (setter)JitCpu_set_X25 , "X25" , NULL}, + {"X26" , (getter)JitCpu_get_X26 , (setter)JitCpu_set_X26 , "X26" , NULL}, + {"X27" , (getter)JitCpu_get_X27 , (setter)JitCpu_set_X27 , "X27" , NULL}, + {"X28" , (getter)JitCpu_get_X28 , (setter)JitCpu_set_X28 , "X28" , NULL}, + {"X29" , (getter)JitCpu_get_X29 , (setter)JitCpu_set_X29 , "X29" , NULL}, + + {"LR" , (getter)JitCpu_get_LR , (setter)JitCpu_set_LR , "LR" , NULL}, + + + + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + + {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL}, + {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL}, + {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL}, + {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_aarch64.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_aarch64_Methods[] = { + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + +MOD_INIT(JitCore_aarch64) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_aarch64", "JitCore_aarch64 module", JitCore_aarch64_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} + diff --git a/src/miasm/jitter/arch/JitCore_aarch64.h b/src/miasm/jitter/arch/JitCore_aarch64.h new file mode 100644 index 00000000..975a93ec --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_aarch64.h @@ -0,0 +1,57 @@ + +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + /* gpregs */ + + uint64_t X0; + uint64_t X1; + uint64_t X2; + uint64_t X3; + uint64_t X4; + uint64_t X5; + uint64_t X6; + uint64_t X7; + uint64_t X8; + uint64_t X9; + uint64_t X10; + uint64_t X11; + uint64_t X12; + uint64_t X13; + uint64_t X14; + uint64_t X15; + uint64_t X16; + uint64_t X17; + uint64_t X18; + uint64_t X19; + uint64_t X20; + uint64_t X21; + uint64_t X22; + uint64_t X23; + uint64_t X24; + uint64_t X25; + uint64_t X26; + uint64_t X27; + uint64_t X28; + uint64_t X29; + uint64_t LR; + uint64_t SP; + + uint64_t PC; + + /* eflag */ + uint32_t zf; + uint32_t nf; + uint32_t of; + uint32_t cf; +}; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/JitCore_arm.c b/src/miasm/jitter/arch/JitCore_arm.c new file mode 100644 index 00000000..b39ae4d2 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_arm.c @@ -0,0 +1,453 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_arm.h" + + + +reg_dict gpreg_dict[] = { + {.name = "R0", .offset = offsetof(struct vm_cpu, R0), .size = 32}, + {.name = "R1", .offset = offsetof(struct vm_cpu, R1), .size = 32}, + {.name = "R2", .offset = offsetof(struct vm_cpu, R2), .size = 32}, + {.name = "R3", .offset = offsetof(struct vm_cpu, R3), .size = 32}, + {.name = "R4", .offset = offsetof(struct vm_cpu, R4), .size = 32}, + {.name = "R5", .offset = offsetof(struct vm_cpu, R5), .size = 32}, + {.name = "R6", .offset = offsetof(struct vm_cpu, R6), .size = 32}, + {.name = "R7", .offset = offsetof(struct vm_cpu, R7), .size = 32}, + {.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 32}, + {.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 32}, + {.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 32}, + {.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 32}, + {.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 32}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32}, + {.name = "LR", .offset = offsetof(struct vm_cpu, LR), .size = 32}, + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8}, + {.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8}, + + {.name = "ge0", .offset = offsetof(struct vm_cpu, ge0), .size = 8}, + {.name = "ge1", .offset = offsetof(struct vm_cpu, ge1), .size = 8}, + {.name = "ge2", .offset = offsetof(struct vm_cpu, ge2), .size = 8}, + {.name = "ge3", .offset = offsetof(struct vm_cpu, ge3), .size = 8}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, +}; + +/************************** JitCpu object **************************/ + + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(R0); + get_reg(R1); + get_reg(R2); + get_reg(R3); + get_reg(R4); + get_reg(R5); + get_reg(R6); + get_reg(R7); + get_reg(R8); + get_reg(R9); + get_reg(R10); + get_reg(R11); + get_reg(R12); + get_reg(SP); + get_reg(LR); + get_reg(PC); + + get_reg(zf); + get_reg(nf); + get_reg(of); + get_reg(cf); + + get_reg(ge0); + get_reg(ge1); + get_reg(ge2); + get_reg(ge3); + + return dict; +} + + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("R0 %.8"PRIX32" R1 %.8"PRIX32" R2 %.8"PRIX32" R3 %.8"PRIX32" ", + vmcpu->R0, vmcpu->R1, vmcpu->R2, vmcpu->R3); + printf("R4 %.8"PRIX32" R5 %.8"PRIX32" R6 %.8"PRIX32" R7 %.8"PRIX32"\n", + vmcpu->R4, vmcpu->R5, vmcpu->R6, vmcpu->R7); + printf("R8 %.8"PRIX32" R9 %.8"PRIX32" R10 %.8"PRIX32" R11 %.8"PRIX32" ", + vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11); + printf("R12 %.8"PRIX32" SP %.8"PRIX32" LR %.8"PRIX32" PC %.8"PRIX32" ", + vmcpu->R12, vmcpu->SP, vmcpu->LR, vmcpu->PC); + printf("zf %"PRIX32" nf %"PRIX32" of %"PRIX32" cf %"PRIX32"\n", + vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num)); +} + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS, + "X"}, + {"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u32(R0); +getset_reg_u32(R1); +getset_reg_u32(R2); +getset_reg_u32(R3); +getset_reg_u32(R4); +getset_reg_u32(R5); +getset_reg_u32(R6); +getset_reg_u32(R7); +getset_reg_u32(R8); +getset_reg_u32(R9); +getset_reg_u32(R10); +getset_reg_u32(R11); +getset_reg_u32(R12); +getset_reg_u32(SP); +getset_reg_u32(LR); +getset_reg_u32(PC); + +getset_reg_u32(zf); +getset_reg_u32(nf); +getset_reg_u32(of); +getset_reg_u32(cf); + +getset_reg_u32(ge0); +getset_reg_u32(ge1); +getset_reg_u32(ge2); +getset_reg_u32(ge3); + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + get_reg_off(interrupt_num); + + get_reg_off(R0); + get_reg_off(R1); + get_reg_off(R2); + get_reg_off(R3); + get_reg_off(R4); + get_reg_off(R5); + get_reg_off(R6); + get_reg_off(R7); + get_reg_off(R8); + get_reg_off(R9); + get_reg_off(R10); + get_reg_off(R11); + get_reg_off(R12); + get_reg_off(SP); + get_reg_off(LR); + get_reg_off(PC); + + /* eflag */ + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(of); + get_reg_off(cf); + + get_reg_off(ge0); + get_reg_off(ge1); + get_reg_off(ge2); + get_reg_off(ge3); + + return dict; +} + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + + {"R0" , (getter)JitCpu_get_R0 , (setter)JitCpu_set_R0 , "R0" , NULL}, + {"R1" , (getter)JitCpu_get_R1 , (setter)JitCpu_set_R1 , "R1" , NULL}, + {"R2" , (getter)JitCpu_get_R2 , (setter)JitCpu_set_R2 , "R2" , NULL}, + {"R3" , (getter)JitCpu_get_R3 , (setter)JitCpu_set_R3 , "R3" , NULL}, + {"R4" , (getter)JitCpu_get_R4 , (setter)JitCpu_set_R4 , "R4" , NULL}, + {"R5" , (getter)JitCpu_get_R5 , (setter)JitCpu_set_R5 , "R5" , NULL}, + {"R6" , (getter)JitCpu_get_R6 , (setter)JitCpu_set_R6 , "R6" , NULL}, + {"R7" , (getter)JitCpu_get_R7 , (setter)JitCpu_set_R7 , "R7" , NULL}, + {"R8" , (getter)JitCpu_get_R8 , (setter)JitCpu_set_R8 , "R8" , NULL}, + {"R9" , (getter)JitCpu_get_R9 , (setter)JitCpu_set_R9 , "R9" , NULL}, + {"R10", (getter)JitCpu_get_R10, (setter)JitCpu_set_R10, "R10", NULL}, + {"R11", (getter)JitCpu_get_R11, (setter)JitCpu_set_R11, "R11", NULL}, + {"R12", (getter)JitCpu_get_R12, (setter)JitCpu_set_R12, "R12", NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + {"LR" , (getter)JitCpu_get_LR , (setter)JitCpu_set_LR , "LR" , NULL}, + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + + {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL}, + {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL}, + {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL}, + {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL}, + + {"ge0", (getter)JitCpu_get_ge0, (setter)JitCpu_set_ge0, "ge0", NULL}, + {"ge1", (getter)JitCpu_get_ge1, (setter)JitCpu_set_ge1, "ge1", NULL}, + {"ge2", (getter)JitCpu_get_ge2, (setter)JitCpu_set_ge2, "ge2", NULL}, + {"ge3", (getter)JitCpu_get_ge3, (setter)JitCpu_set_ge3, "ge3", NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_arm.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_arm_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + +MOD_INIT(JitCore_arm) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_arm", "JitCore_arm module", JitCore_arm_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} + diff --git a/src/miasm/jitter/arch/JitCore_arm.h b/src/miasm/jitter/arch/JitCore_arm.h new file mode 100644 index 00000000..30a38344 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_arm.h @@ -0,0 +1,47 @@ + +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + /* gpregs */ + uint32_t R0; + uint32_t R1; + uint32_t R2; + uint32_t R3; + uint32_t R4; + uint32_t R5; + uint32_t R6; + uint32_t R7; + uint32_t R8; + uint32_t R9; + uint32_t R10; + uint32_t R11; + uint32_t R12; + uint32_t SP; + uint32_t LR; + uint32_t PC; + + /* eflag */ + uint32_t zf; + uint32_t nf; + uint32_t of; + uint32_t cf; + + /* ge */ + uint32_t ge0; + uint32_t ge1; + uint32_t ge2; + uint32_t ge3; + + uint32_t bp_num; +}; + + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/JitCore_m68k.c b/src/miasm/jitter/arch/JitCore_m68k.c new file mode 100644 index 00000000..0989fde1 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_m68k.c @@ -0,0 +1,467 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_m68k.h" + + + +reg_dict gpreg_dict[] = { + {.name = "A0", .offset = offsetof(struct vm_cpu, A0), .size = 32}, + {.name = "A1", .offset = offsetof(struct vm_cpu, A1), .size = 32}, + {.name = "A2", .offset = offsetof(struct vm_cpu, A2), .size = 32}, + {.name = "A3", .offset = offsetof(struct vm_cpu, A3), .size = 32}, + {.name = "A4", .offset = offsetof(struct vm_cpu, A4), .size = 32}, + {.name = "A5", .offset = offsetof(struct vm_cpu, A5), .size = 32}, + {.name = "A6", .offset = offsetof(struct vm_cpu, A6), .size = 32}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32}, + + {.name = "D0", .offset = offsetof(struct vm_cpu, D0), .size = 32}, + {.name = "D1", .offset = offsetof(struct vm_cpu, D1), .size = 32}, + {.name = "D2", .offset = offsetof(struct vm_cpu, D2), .size = 32}, + {.name = "D3", .offset = offsetof(struct vm_cpu, D3), .size = 32}, + {.name = "D4", .offset = offsetof(struct vm_cpu, D4), .size = 32}, + {.name = "D5", .offset = offsetof(struct vm_cpu, D5), .size = 32}, + {.name = "D6", .offset = offsetof(struct vm_cpu, D6), .size = 32}, + {.name = "D7", .offset = offsetof(struct vm_cpu, D7), .size = 32}, + + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8}, + {.name = "vf", .offset = offsetof(struct vm_cpu, vf), .size = 8}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8}, + {.name = "xf", .offset = offsetof(struct vm_cpu, xf), .size = 8}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, +}; + +/************************** JitCpu object **************************/ + + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(A0); + get_reg(A1); + get_reg(A2); + get_reg(A3); + get_reg(A4); + get_reg(A5); + get_reg(A6); + get_reg(SP); + + get_reg(D0); + get_reg(D1); + get_reg(D2); + get_reg(D3); + get_reg(D4); + get_reg(D5); + get_reg(D6); + get_reg(D7); + + get_reg(PC); + + get_reg(zf); + get_reg(nf); + get_reg(vf); + get_reg(cf); + get_reg(xf); + + return dict; +} + + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; +} + + +uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr) +{ + return addr; +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("A0 %.8"PRIX32" A1 %.8"PRIX32" A2 %.8"PRIX32" A3 %.8"PRIX32" ", + vmcpu->A0, vmcpu->A1, vmcpu->A2, vmcpu->A3); + printf("R4 %.8"PRIX32" A5 %.8"PRIX32" A6 %.8"PRIX32" SP %.8"PRIX32"\n", + vmcpu->A4, vmcpu->A5, vmcpu->A6, vmcpu->SP); + + printf("D0 %.8"PRIX32" D1 %.8"PRIX32" D2 %.8"PRIX32" D3 %.8"PRIX32" ", + vmcpu->D0, vmcpu->D1, vmcpu->D2, vmcpu->D3); + printf("R4 %.8"PRIX32" D5 %.8"PRIX32" D6 %.8"PRIX32" D7 %.8"PRIX32"\n", + vmcpu->D4, vmcpu->D5, vmcpu->D6, vmcpu->D7); + + + printf("PC %.8"PRIX32" ", + vmcpu->PC); + printf("zf %"PRIX32" nf %"PRIX32" vf %"PRIX32" cf %"PRIX32" xf %"PRIX32"\n", + vmcpu->zf, vmcpu->nf, vmcpu->vf, vmcpu->cf, vmcpu->xf); +} + +void dump_gpregs_32(struct vm_cpu* vmcpu) +{ + dump_gpregs(vmcpu); +} + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num)); +} + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS, + "X"}, + {"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u32(A0); +getset_reg_u32(A1); +getset_reg_u32(A2); +getset_reg_u32(A3); +getset_reg_u32(A4); +getset_reg_u32(A5); +getset_reg_u32(A6); +getset_reg_u32(SP); + +getset_reg_u32(D0); +getset_reg_u32(D1); +getset_reg_u32(D2); +getset_reg_u32(D3); +getset_reg_u32(D4); +getset_reg_u32(D5); +getset_reg_u32(D6); +getset_reg_u32(D7); +getset_reg_u32(PC); + +getset_reg_u32(zf); +getset_reg_u32(nf); +getset_reg_u32(vf); +getset_reg_u32(cf); +getset_reg_u32(xf); + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + get_reg_off(interrupt_num); + + get_reg_off(A0); + get_reg_off(A1); + get_reg_off(A2); + get_reg_off(A3); + get_reg_off(A4); + get_reg_off(A5); + get_reg_off(A6); + get_reg_off(SP); + + get_reg_off(D0); + get_reg_off(D1); + get_reg_off(D2); + get_reg_off(D3); + get_reg_off(D4); + get_reg_off(D5); + get_reg_off(D6); + get_reg_off(D7); + + get_reg_off(PC); + + /* eflag */ + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(vf); + get_reg_off(cf); + get_reg_off(xf); + + return dict; +} + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"vmcpu", + (getter)JitCpu_get_vmcpu, (setter)JitCpu_set_vmcpu, + "vmcpu", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + + {"A0" , (getter)JitCpu_get_A0 , (setter)JitCpu_set_A0 , "A0" , NULL}, + {"A1" , (getter)JitCpu_get_A1 , (setter)JitCpu_set_A1 , "A1" , NULL}, + {"A2" , (getter)JitCpu_get_A2 , (setter)JitCpu_set_A2 , "A2" , NULL}, + {"A3" , (getter)JitCpu_get_A3 , (setter)JitCpu_set_A3 , "A3" , NULL}, + {"A4" , (getter)JitCpu_get_A4 , (setter)JitCpu_set_A4 , "A4" , NULL}, + {"A5" , (getter)JitCpu_get_A5 , (setter)JitCpu_set_A5 , "A5" , NULL}, + {"A6" , (getter)JitCpu_get_A6 , (setter)JitCpu_set_A6 , "A6" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + + {"D0" , (getter)JitCpu_get_D0 , (setter)JitCpu_set_D0 , "D0" , NULL}, + {"D1" , (getter)JitCpu_get_D1 , (setter)JitCpu_set_D1 , "D1" , NULL}, + {"D2" , (getter)JitCpu_get_D2 , (setter)JitCpu_set_D2 , "D2" , NULL}, + {"D3" , (getter)JitCpu_get_D3 , (setter)JitCpu_set_D3 , "D3" , NULL}, + {"D4" , (getter)JitCpu_get_D4 , (setter)JitCpu_set_D4 , "D4" , NULL}, + {"D5" , (getter)JitCpu_get_D5 , (setter)JitCpu_set_D5 , "D5" , NULL}, + {"D6" , (getter)JitCpu_get_D6 , (setter)JitCpu_set_D6 , "D6" , NULL}, + {"D7" , (getter)JitCpu_get_D7 , (setter)JitCpu_set_D7 , "D7" , NULL}, + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + + {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL}, + {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL}, + {"vf", (getter)JitCpu_get_vf, (setter)JitCpu_set_vf, "vf", NULL}, + {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL}, + {"xf", (getter)JitCpu_get_xf, (setter)JitCpu_set_xf, "xf", NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_m68k.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_m68k_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + +MOD_INIT(JitCore_m68k) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_m68k", "JitCore_m68k module", JitCore_m68k_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} + diff --git a/src/miasm/jitter/arch/JitCore_m68k.h b/src/miasm/jitter/arch/JitCore_m68k.h new file mode 100644 index 00000000..6ff6b326 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_m68k.h @@ -0,0 +1,55 @@ + +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + /* gpregs */ + uint32_t A0; + uint32_t A1; + uint32_t A2; + uint32_t A3; + uint32_t A4; + uint32_t A5; + uint32_t A6; + uint32_t SP; + + uint32_t D0; + uint32_t D1; + uint32_t D2; + uint32_t D3; + uint32_t D4; + uint32_t D5; + uint32_t D6; + uint32_t D7; + + + uint32_t PC; + + /* eflag */ + uint32_t zf; + uint32_t nf; + uint32_t vf; + uint32_t cf; + uint32_t xf; + + uint64_t float_st0; + uint64_t float_st1; + uint64_t float_st2; + uint64_t float_st3; + uint64_t float_st4; + uint64_t float_st5; + uint64_t float_st6; + uint64_t float_st7; + + uint32_t bp_num; +}; + + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/JitCore_mep.c b/src/miasm/jitter/arch/JitCore_mep.c new file mode 100644 index 00000000..286a12ac --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_mep.c @@ -0,0 +1,569 @@ +// Inspired from JitCore_mep.c + +#include <Python.h> +#include "structmember.h" +#include <stdint.h> + +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "JitCore_mep.h" + + +reg_dict gpreg_dict[] = { + {.name = "R0", .offset = offsetof(struct vm_cpu, R0), .size = 32}, + {.name = "R1", .offset = offsetof(struct vm_cpu, R1), .size = 32}, + {.name = "R2", .offset = offsetof(struct vm_cpu, R2), .size = 32}, + {.name = "R3", .offset = offsetof(struct vm_cpu, R3), .size = 32}, + {.name = "R4", .offset = offsetof(struct vm_cpu, R4), .size = 32}, + {.name = "R5", .offset = offsetof(struct vm_cpu, R5), .size = 32}, + {.name = "R6", .offset = offsetof(struct vm_cpu, R6), .size = 32}, + {.name = "R7", .offset = offsetof(struct vm_cpu, R7), .size = 32}, + {.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 32}, + {.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 32}, + {.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 32}, + {.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 32}, + {.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 32}, + {.name = "TP", .offset = offsetof(struct vm_cpu, TP), .size = 32}, + {.name = "GP", .offset = offsetof(struct vm_cpu, GP), .size = 32}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32}, + + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32}, + {.name = "LP", .offset = offsetof(struct vm_cpu, LP), .size = 32}, + {.name = "SAR", .offset = offsetof(struct vm_cpu, SAR), .size = 32}, + {.name = "S3", .offset = offsetof(struct vm_cpu, S3), .size = 32}, + {.name = "RPB", .offset = offsetof(struct vm_cpu, RPB), .size = 32}, + {.name = "RPE", .offset = offsetof(struct vm_cpu, RPE), .size = 32}, + {.name = "RPC", .offset = offsetof(struct vm_cpu, RPC), .size = 32}, + {.name = "HI", .offset = offsetof(struct vm_cpu, HI), .size = 32}, + {.name = "LO", .offset = offsetof(struct vm_cpu, LO), .size = 32}, + {.name = "S9", .offset = offsetof(struct vm_cpu, S9), .size = 32}, + {.name = "S10", .offset = offsetof(struct vm_cpu, S10), .size = 32}, + {.name = "S11", .offset = offsetof(struct vm_cpu, S11), .size = 32}, + {.name = "MB0", .offset = offsetof(struct vm_cpu, MB0), .size = 32}, + {.name = "ME0", .offset = offsetof(struct vm_cpu, ME0), .size = 32}, + {.name = "MB1", .offset = offsetof(struct vm_cpu, MB1), .size = 32}, + {.name = "ME1", .offset = offsetof(struct vm_cpu, ME1), .size = 32}, + {.name = "PSW", .offset = offsetof(struct vm_cpu, PSW), .size = 32}, + {.name = "ID", .offset = offsetof(struct vm_cpu, ID), .size = 32}, + {.name = "TMP", .offset = offsetof(struct vm_cpu, TMP), .size = 32}, + {.name = "EPC", .offset = offsetof(struct vm_cpu, EPC), .size = 32}, + {.name = "EXC", .offset = offsetof(struct vm_cpu, EXC), .size = 32}, + {.name = "CFG", .offset = offsetof(struct vm_cpu, CFG), .size = 32}, + {.name = "S22", .offset = offsetof(struct vm_cpu, S22), .size = 32}, + {.name = "NPC", .offset = offsetof(struct vm_cpu, NPC), .size = 32}, + {.name = "DBG", .offset = offsetof(struct vm_cpu, DBG), .size = 32}, + {.name = "DEPC", .offset = offsetof(struct vm_cpu, DEPC), .size = 32}, + {.name = "OPT", .offset = offsetof(struct vm_cpu, OPT), .size = 32}, + {.name = "RCFG", .offset = offsetof(struct vm_cpu, RCFG), .size = 32}, + {.name = "CCFG", .offset = offsetof(struct vm_cpu, CCFG), .size = 32}, + {.name = "S29", .offset = offsetof(struct vm_cpu, S29), .size = 32}, + {.name = "S30", .offset = offsetof(struct vm_cpu, S30), .size = 32}, + {.name = "S31", .offset = offsetof(struct vm_cpu, S31), .size = 32}, + {.name = "S32", .offset = offsetof(struct vm_cpu, S32), .size = 32}, + {.name = "take_jmp", .offset = offsetof(struct vm_cpu, take_jmp), .size = 32}, + {.name = "last_addr", .offset = offsetof(struct vm_cpu, last_addr), .size = 32}, + {.name = "is_repeat_end", .offset = offsetof(struct vm_cpu, is_repeat_end), .size = 32}, + + {.name = "PC_end", .offset = offsetof(struct vm_cpu, PC_end), .size = 32}, + {.name = "RPE_instr_count", .offset = offsetof(struct vm_cpu, RPE_instr_count), .size = 32}, + {.name = "RPC_current", .offset = offsetof(struct vm_cpu, RPC_current), .size = 32}, + +}; + +/************************** JitCpu object **************************/ + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(R0); + get_reg(R1); + get_reg(R2); + get_reg(R3); + get_reg(R4); + get_reg(R5); + get_reg(R6); + get_reg(R7); + get_reg(R8); + get_reg(R9); + get_reg(R10); + get_reg(R11); + get_reg(R12); + get_reg(TP); + get_reg(GP); + get_reg(SP); + + get_reg(PC); + get_reg(LP); + get_reg(SAR); + get_reg(S3); + get_reg(RPB); + get_reg(RPE); + get_reg(RPC); + get_reg(HI); + get_reg(LO); + get_reg(S9); + get_reg(S10); + get_reg(S11); + get_reg(MB0); + get_reg(ME0); + get_reg(MB1); + get_reg(ME1); + get_reg(PSW); + get_reg(ID); + get_reg(TMP); + get_reg(EPC); + get_reg(EXC); + get_reg(CFG); + get_reg(S22); + get_reg(NPC); + get_reg(DBG); + get_reg(DEPC); + get_reg(OPT); + get_reg(RCFG); + get_reg(CCFG); + get_reg(S29); + get_reg(S30); + get_reg(S31); + get_reg(S32); + + get_reg(PC_end); + get_reg(RPE_instr_count); + get_reg(RPC_current); + + + return dict; +} + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + return NULL; + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; + +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + printf("R0 %.4"PRIX32" ", vmcpu->R0); + printf("R1 %.4"PRIX32" ", vmcpu->R1); + printf("R2 %.4"PRIX32" ", vmcpu->R2); + printf("R3 %.4"PRIX32" ", vmcpu->R3); + printf("R4 %.4"PRIX32" ", vmcpu->R4); + printf("R5 %.4"PRIX32" ", vmcpu->R5); + printf("R6 %.4"PRIX32" ", vmcpu->R6); + printf("R7 %.4"PRIX32" ", vmcpu->R7); + printf("R8 %.4"PRIX32" ", vmcpu->R8); + printf("R9 %.4"PRIX32" ", vmcpu->R9); + printf("R10 %.4"PRIX32" ", vmcpu->R10); + printf("R11 %.4"PRIX32" ", vmcpu->R11); + printf("R12 %.4"PRIX32" ", vmcpu->R12); + printf("TP %.4"PRIX32" ", vmcpu->TP); + printf("GP %.4"PRIX32" ", vmcpu->GP); + printf("SP %.4"PRIX32" ", vmcpu->SP); + printf("\n"); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + return NULL; + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(0); + } + return 0; +} + +getset_reg_u32(R0); +getset_reg_u32(R1); +getset_reg_u32(R2); +getset_reg_u32(R3); +getset_reg_u32(R4); +getset_reg_u32(R5); +getset_reg_u32(R6); +getset_reg_u32(R7); +getset_reg_u32(R8); +getset_reg_u32(R9); +getset_reg_u32(R10); +getset_reg_u32(R11); +getset_reg_u32(R12); +getset_reg_u32(TP); +getset_reg_u32(GP); +getset_reg_u32(SP); + +getset_reg_u32(PC); +getset_reg_u32(LP); +getset_reg_u32(SAR); +getset_reg_u32(S3); +getset_reg_u32(RPB); +getset_reg_u32(RPE); +getset_reg_u32(RPC); +getset_reg_u32(HI); +getset_reg_u32(LO); +getset_reg_u32(S9); +getset_reg_u32(S10); +getset_reg_u32(S11); +getset_reg_u32(MB0); +getset_reg_u32(ME0); +getset_reg_u32(MB1); +getset_reg_u32(ME1); +getset_reg_u32(PSW); +getset_reg_u32(ID); +getset_reg_u32(TMP); +getset_reg_u32(EPC); +getset_reg_u32(EXC); +getset_reg_u32(CFG); +getset_reg_u32(S22); +getset_reg_u32(NPC); +getset_reg_u32(DBG); +getset_reg_u32(DEPC); +getset_reg_u32(OPT); +getset_reg_u32(RCFG); +getset_reg_u32(CCFG); +getset_reg_u32(S29); +getset_reg_u32(S30); +getset_reg_u32(S31); +getset_reg_u32(S32); + +getset_reg_u32(PC_end); +getset_reg_u32(RPE_instr_count); +getset_reg_u32(RPC_current); + + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + get_reg_off(exception_flags); + + get_reg_off(R0); + get_reg_off(R1); + get_reg_off(R2); + get_reg_off(R3); + get_reg_off(R4); + get_reg_off(R5); + get_reg_off(R6); + get_reg_off(R7); + get_reg_off(R8); + get_reg_off(R9); + get_reg_off(R10); + get_reg_off(R11); + get_reg_off(R12); + get_reg_off(TP); + get_reg_off(GP); + get_reg_off(SP); + + get_reg_off(PC); + get_reg_off(LP); + get_reg_off(SAR); + get_reg_off(S3); + get_reg_off(RPB); + get_reg_off(RPE); + get_reg_off(RPC); + get_reg_off(HI); + get_reg_off(LO); + get_reg_off(S9); + get_reg_off(S10); + get_reg_off(S11); + get_reg_off(MB0); + get_reg_off(ME0); + get_reg_off(MB1); + get_reg_off(ME1); + get_reg_off(PSW); + get_reg_off(ID); + get_reg_off(TMP); + get_reg_off(EPC); + get_reg_off(EXC); + get_reg_off(CFG); + get_reg_off(S22); + get_reg_off(NPC); + get_reg_off(DBG); + get_reg_off(DEPC); + get_reg_off(OPT); + get_reg_off(RCFG); + get_reg_off(CCFG); + get_reg_off(S29); + get_reg_off(S30); + get_reg_off(S31); + get_reg_off(S32); + + get_reg_off(PC_end); + get_reg_off(RPE_instr_count); + get_reg_off(RPC_current); + + + return dict; +} + + + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + {"R0" , (getter)JitCpu_get_R0 , (setter)JitCpu_set_R0 , "R0" , NULL}, + {"R1" , (getter)JitCpu_get_R1 , (setter)JitCpu_set_R1 , "R1" , NULL}, + {"R2" , (getter)JitCpu_get_R2 , (setter)JitCpu_set_R2 , "R2" , NULL}, + {"R3" , (getter)JitCpu_get_R3 , (setter)JitCpu_set_R3 , "R3" , NULL}, + {"R4" , (getter)JitCpu_get_R4 , (setter)JitCpu_set_R4 , "R4" , NULL}, + {"R5" , (getter)JitCpu_get_R5 , (setter)JitCpu_set_R5 , "R5" , NULL}, + {"R6" , (getter)JitCpu_get_R6 , (setter)JitCpu_set_R6 , "R6" , NULL}, + {"R7" , (getter)JitCpu_get_R7 , (setter)JitCpu_set_R7 , "R7" , NULL}, + {"R8" , (getter)JitCpu_get_R8 , (setter)JitCpu_set_R8 , "R8" , NULL}, + {"R9" , (getter)JitCpu_get_R9 , (setter)JitCpu_set_R9 , "R9" , NULL}, + {"R10" , (getter)JitCpu_get_R10 , (setter)JitCpu_set_R10 , "R10" , NULL}, + {"R11" , (getter)JitCpu_get_R11 , (setter)JitCpu_set_R11 , "R11" , NULL}, + {"R12" , (getter)JitCpu_get_R12 , (setter)JitCpu_set_R12 , "R12" , NULL}, + {"TP" , (getter)JitCpu_get_TP , (setter)JitCpu_set_TP , "TP" , NULL}, + {"GP" , (getter)JitCpu_get_GP , (setter)JitCpu_set_GP , "GP" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + {"LP" , (getter)JitCpu_get_LP , (setter)JitCpu_set_LP , "LP" , NULL}, + {"SAR" , (getter)JitCpu_get_SAR , (setter)JitCpu_set_SAR , "SAR" , NULL}, + {"S3" , (getter)JitCpu_get_S3 , (setter)JitCpu_set_S3 , "S3" , NULL}, + {"RPB" , (getter)JitCpu_get_RPB , (setter)JitCpu_set_RPB , "RPB" , NULL}, + {"RPE" , (getter)JitCpu_get_RPE , (setter)JitCpu_set_RPE , "RPE" , NULL}, + {"RPC" , (getter)JitCpu_get_RPC , (setter)JitCpu_set_RPC , "RPC" , NULL}, + {"HI" , (getter)JitCpu_get_HI , (setter)JitCpu_set_HI , "HI" , NULL}, + {"LO" , (getter)JitCpu_get_LO , (setter)JitCpu_set_LO , "LO" , NULL}, + {"S9" , (getter)JitCpu_get_S9 , (setter)JitCpu_set_S9 , "S9" , NULL}, + {"S10" , (getter)JitCpu_get_S10 , (setter)JitCpu_set_S10 , "S10" , NULL}, + {"S11" , (getter)JitCpu_get_S11 , (setter)JitCpu_set_S11 , "S11" , NULL}, + {"MB0" , (getter)JitCpu_get_MB0 , (setter)JitCpu_set_MB0 , "MB0" , NULL}, + {"ME0" , (getter)JitCpu_get_ME0 , (setter)JitCpu_set_ME0 , "ME0" , NULL}, + {"MB1" , (getter)JitCpu_get_MB1 , (setter)JitCpu_set_MB1 , "MB1" , NULL}, + {"ME1" , (getter)JitCpu_get_ME1 , (setter)JitCpu_set_ME1 , "ME1" , NULL}, + {"PSW" , (getter)JitCpu_get_PSW , (setter)JitCpu_set_PSW , "PSW" , NULL}, + {"ID" , (getter)JitCpu_get_ID , (setter)JitCpu_set_ID , "ID" , NULL}, + {"TMP" , (getter)JitCpu_get_TMP , (setter)JitCpu_set_TMP , "TMP" , NULL}, + {"EPC" , (getter)JitCpu_get_EPC , (setter)JitCpu_set_EPC , "EPC" , NULL}, + {"EXC" , (getter)JitCpu_get_EXC , (setter)JitCpu_set_EXC , "EXC" , NULL}, + {"CFG" , (getter)JitCpu_get_CFG , (setter)JitCpu_set_CFG , "CFG" , NULL}, + {"S22" , (getter)JitCpu_get_S22 , (setter)JitCpu_set_S22 , "S22" , NULL}, + {"NPC" , (getter)JitCpu_get_NPC , (setter)JitCpu_set_NPC , "NPC" , NULL}, + {"DBG" , (getter)JitCpu_get_DBG , (setter)JitCpu_set_DBG , "DBG" , NULL}, + {"DEPC" , (getter)JitCpu_get_DEPC , (setter)JitCpu_set_DEPC , "DEPC" , NULL}, + {"OPT" , (getter)JitCpu_get_OPT , (setter)JitCpu_set_OPT , "OPT" , NULL}, + {"RCFG" , (getter)JitCpu_get_RCFG , (setter)JitCpu_set_RCFG , "RCFG" , NULL}, + {"CCFG" , (getter)JitCpu_get_CCFG , (setter)JitCpu_set_CCFG , "CCFG" , NULL}, + {"S29" , (getter)JitCpu_get_S29 , (setter)JitCpu_set_S29 , "S29" , NULL}, + {"S30" , (getter)JitCpu_get_S30 , (setter)JitCpu_set_S30 , "S30" , NULL}, + {"S31" , (getter)JitCpu_get_S31 , (setter)JitCpu_set_S31 , "S31" , NULL}, + {"S32" , (getter)JitCpu_get_S32 , (setter)JitCpu_set_S32 , "S32" , NULL}, + + {"PC_end" , (getter)JitCpu_get_PC_end , (setter)JitCpu_set_PC_end , "PC_end" , NULL}, + {"RPE_instr_count" , (getter)JitCpu_get_RPE_instr_count , (setter)JitCpu_set_RPE_instr_count , "RPE_instr_count" , NULL}, + {"RPC_current" , (getter)JitCpu_get_RPC_current , (setter)JitCpu_set_RPC_current , "RPC_current" , NULL}, + + + + {NULL} /* Sentinel */ +}; + + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_mep.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_mep_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + +MOD_INIT(JitCore_mep) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_mep", "JitCore_mep module", JitCore_mep_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} diff --git a/src/miasm/jitter/arch/JitCore_mep.h b/src/miasm/jitter/arch/JitCore_mep.h new file mode 100644 index 00000000..f656b3a0 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_mep.h @@ -0,0 +1,82 @@ +// Inspired from JitCore_msp430.h + +struct vm_cpu { + /* miasm flags */ + uint32_t exception_flags; + + /* gpregs */ + uint32_t R0; + uint32_t R1; + uint32_t R2; + uint32_t R3; + uint32_t R4; + uint32_t R5; + uint32_t R6; + uint32_t R7; + uint32_t R8; + uint32_t R9; + uint32_t R10; + uint32_t R11; + uint32_t R12; + uint32_t TP; + uint32_t GP; + uint32_t SP; + + /* csregs */ + uint32_t PC; + uint32_t LP; + uint32_t SAR; + uint32_t S3; + uint32_t RPB; + uint32_t RPE; + uint32_t RPC; + uint32_t HI; + uint32_t LO; + uint32_t S9; + uint32_t S10; + uint32_t S11; + uint32_t MB0; + uint32_t ME0; + uint32_t MB1; + uint32_t ME1; + uint32_t PSW; + uint32_t ID; + uint32_t TMP; + uint32_t EPC; + uint32_t EXC; + uint32_t CFG; + uint32_t S22; + uint32_t NPC; + uint32_t DBG; + uint32_t DEPC; + uint32_t OPT; + uint32_t RCFG; + uint32_t CCFG; + uint32_t S29; + uint32_t S30; + uint32_t S31; + uint32_t S32; + + /* miasm specific regs */ + uint32_t PC_end; + uint32_t RPE_instr_count; + uint32_t RPC_current; + + + uint32_t take_jmp; + uint32_t last_addr; + uint32_t is_repeat_end; + uint32_t in_erepeat; + + /* flags */ + +}; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/JitCore_mips32.c b/src/miasm/jitter/arch/JitCore_mips32.c new file mode 100644 index 00000000..1d7a762c --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_mips32.c @@ -0,0 +1,484 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_mips32.h" + + + +reg_dict gpreg_dict[] = { {.name = "ZERO", .offset = offsetof(struct vm_cpu, ZERO), .size = 32}, + {.name = "AT", .offset = offsetof(struct vm_cpu, AT), .size = 32}, + {.name = "V0", .offset = offsetof(struct vm_cpu, V0), .size = 32}, + {.name = "V1", .offset = offsetof(struct vm_cpu, V1), .size = 32}, + {.name = "A0", .offset = offsetof(struct vm_cpu, A0), .size = 32}, + {.name = "A1", .offset = offsetof(struct vm_cpu, A1), .size = 32}, + {.name = "A2", .offset = offsetof(struct vm_cpu, A2), .size = 32}, + {.name = "A3", .offset = offsetof(struct vm_cpu, A3), .size = 32}, + {.name = "T0", .offset = offsetof(struct vm_cpu, T0), .size = 32}, + {.name = "T1", .offset = offsetof(struct vm_cpu, T1), .size = 32}, + {.name = "T2", .offset = offsetof(struct vm_cpu, T2), .size = 32}, + {.name = "T3", .offset = offsetof(struct vm_cpu, T3), .size = 32}, + {.name = "T4", .offset = offsetof(struct vm_cpu, T4), .size = 32}, + {.name = "T5", .offset = offsetof(struct vm_cpu, T5), .size = 32}, + {.name = "T6", .offset = offsetof(struct vm_cpu, T6), .size = 32}, + {.name = "T7", .offset = offsetof(struct vm_cpu, T7), .size = 32}, + {.name = "S0", .offset = offsetof(struct vm_cpu, S0), .size = 32}, + {.name = "S1", .offset = offsetof(struct vm_cpu, S1), .size = 32}, + {.name = "S2", .offset = offsetof(struct vm_cpu, S2), .size = 32}, + {.name = "S3", .offset = offsetof(struct vm_cpu, S3), .size = 32}, + {.name = "S4", .offset = offsetof(struct vm_cpu, S4), .size = 32}, + {.name = "S5", .offset = offsetof(struct vm_cpu, S5), .size = 32}, + {.name = "S6", .offset = offsetof(struct vm_cpu, S6), .size = 32}, + {.name = "S7", .offset = offsetof(struct vm_cpu, S7), .size = 32}, + {.name = "T8", .offset = offsetof(struct vm_cpu, T8), .size = 32}, + {.name = "T9", .offset = offsetof(struct vm_cpu, T9), .size = 32}, + {.name = "K0", .offset = offsetof(struct vm_cpu, K0), .size = 32}, + {.name = "K1", .offset = offsetof(struct vm_cpu, K1), .size = 32}, + {.name = "GP", .offset = offsetof(struct vm_cpu, GP), .size = 32}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP), .size = 32}, + {.name = "FP", .offset = offsetof(struct vm_cpu, FP), .size = 32}, + {.name = "RA", .offset = offsetof(struct vm_cpu, RA), .size = 32}, + {.name = "PC", .offset = offsetof(struct vm_cpu, PC), .size = 32}, + {.name = "PC_FETCH", .offset = offsetof(struct vm_cpu, PC_FETCH), .size = 32}, + {.name = "R_LO", .offset = offsetof(struct vm_cpu, R_LO), .size = 32}, + {.name = "R_HI", .offset = offsetof(struct vm_cpu, R_HI), .size = 32}, +}; + +/************************** JitCpu object **************************/ + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(ZERO); + get_reg(AT); + get_reg(V0); + get_reg(V1); + get_reg(A0); + get_reg(A1); + get_reg(A2); + get_reg(A3); + get_reg(T0); + get_reg(T1); + get_reg(T2); + get_reg(T3); + get_reg(T4); + get_reg(T5); + get_reg(T6); + get_reg(T7); + get_reg(S0); + get_reg(S1); + get_reg(S2); + get_reg(S3); + get_reg(S4); + get_reg(S5); + get_reg(S6); + get_reg(S7); + get_reg(T8); + get_reg(T9); + get_reg(K0); + get_reg(K1); + get_reg(GP); + get_reg(SP); + get_reg(FP); + get_reg(RA); + get_reg(PC); + get_reg(PC_FETCH); + get_reg(R_LO); + get_reg(R_HI); + + return dict; +} + + + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; + +} + + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + + printf("ZR %.8"PRIX32" AT %.8"PRIX32" V0 %.8"PRIX32" V1 %.8"PRIX32" ", + vmcpu->ZERO, vmcpu->AT, vmcpu->V0, vmcpu->V1); + printf("A0 %.8"PRIX32" A1 %.8"PRIX32" A2 %.8"PRIX32" A3 %.8"PRIX32" ", + vmcpu->A0, vmcpu->A1, vmcpu->A2, vmcpu->A3); + printf("T0 %.8"PRIX32" T1 %.8"PRIX32" T2 %.8"PRIX32" T3 %.8"PRIX32" ", + vmcpu->T0, vmcpu->T1, vmcpu->T2, vmcpu->T3); + printf("T4 %.8"PRIX32" T5 %.8"PRIX32" T6 %.8"PRIX32" T7 %.8"PRIX32"\n", + vmcpu->T4, vmcpu->T5, vmcpu->T6, vmcpu->T7); + printf("S0 %.8"PRIX32" S1 %.8"PRIX32" S2 %.8"PRIX32" S3 %.8"PRIX32" ", + vmcpu->S0, vmcpu->S1, vmcpu->S2, vmcpu->S3); + printf("S4 %.8"PRIX32" S5 %.8"PRIX32" S6 %.8"PRIX32" S7 %.8"PRIX32" ", + vmcpu->S4, vmcpu->S5, vmcpu->S6, vmcpu->S7); + printf("T8 %.8"PRIX32" T9 %.8"PRIX32" K0 %.8"PRIX32" K1 %.8"PRIX32" ", + vmcpu->T8, vmcpu->T9, vmcpu->K0, vmcpu->K1); + printf("GP %.8"PRIX32" SP %.8"PRIX32" FP %.8"PRIX32" RA %.8"PRIX32"\n", + vmcpu->GP, vmcpu->SP, vmcpu->FP, vmcpu->RA); + printf("PC %.8"PRIX32"\n", + vmcpu->PC); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u32(ZERO); +getset_reg_u32(AT); +getset_reg_u32(V0); +getset_reg_u32(V1); +getset_reg_u32(A0); +getset_reg_u32(A1); +getset_reg_u32(A2); +getset_reg_u32(A3); +getset_reg_u32(T0); +getset_reg_u32(T1); +getset_reg_u32(T2); +getset_reg_u32(T3); +getset_reg_u32(T4); +getset_reg_u32(T5); +getset_reg_u32(T6); +getset_reg_u32(T7); +getset_reg_u32(S0); +getset_reg_u32(S1); +getset_reg_u32(S2); +getset_reg_u32(S3); +getset_reg_u32(S4); +getset_reg_u32(S5); +getset_reg_u32(S6); +getset_reg_u32(S7); +getset_reg_u32(T8); +getset_reg_u32(T9); +getset_reg_u32(K0); +getset_reg_u32(K1); +getset_reg_u32(GP); +getset_reg_u32(SP); +getset_reg_u32(FP); +getset_reg_u32(RA); +getset_reg_u32(PC); +getset_reg_u32(PC_FETCH); +getset_reg_u32(R_LO); +getset_reg_u32(R_HI); + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg_off(exception_flags); + + + get_reg_off(ZERO); + get_reg_off(AT); + get_reg_off(V0); + get_reg_off(V1); + get_reg_off(A0); + get_reg_off(A1); + get_reg_off(A2); + get_reg_off(A3); + get_reg_off(T0); + get_reg_off(T1); + get_reg_off(T2); + get_reg_off(T3); + get_reg_off(T4); + get_reg_off(T5); + get_reg_off(T6); + get_reg_off(T7); + get_reg_off(S0); + get_reg_off(S1); + get_reg_off(S2); + get_reg_off(S3); + get_reg_off(S4); + get_reg_off(S5); + get_reg_off(S6); + get_reg_off(S7); + get_reg_off(T8); + get_reg_off(T9); + get_reg_off(K0); + get_reg_off(K1); + get_reg_off(GP); + get_reg_off(SP); + get_reg_off(FP); + get_reg_off(RA); + get_reg_off(PC); + get_reg_off(PC_FETCH); + get_reg_off(R_LO); + get_reg_off(R_HI); + + return dict; +} + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + {"ZERO" , (getter)JitCpu_get_ZERO , (setter)JitCpu_set_ZERO , "ZERO" , NULL}, + {"AT" , (getter)JitCpu_get_AT , (setter)JitCpu_set_AT , "AT" , NULL}, + {"V0" , (getter)JitCpu_get_V0 , (setter)JitCpu_set_V0 , "V0" , NULL}, + {"V1" , (getter)JitCpu_get_V1 , (setter)JitCpu_set_V1 , "V1" , NULL}, + {"A0" , (getter)JitCpu_get_A0 , (setter)JitCpu_set_A0 , "A0" , NULL}, + {"A1" , (getter)JitCpu_get_A1 , (setter)JitCpu_set_A1 , "A1" , NULL}, + {"A2" , (getter)JitCpu_get_A2 , (setter)JitCpu_set_A2 , "A2" , NULL}, + {"A3" , (getter)JitCpu_get_A3 , (setter)JitCpu_set_A3 , "A3" , NULL}, + {"T0" , (getter)JitCpu_get_T0 , (setter)JitCpu_set_T0 , "T0" , NULL}, + {"T1" , (getter)JitCpu_get_T1 , (setter)JitCpu_set_T1 , "T1" , NULL}, + {"T2" , (getter)JitCpu_get_T2 , (setter)JitCpu_set_T2 , "T2" , NULL}, + {"T3" , (getter)JitCpu_get_T3 , (setter)JitCpu_set_T3 , "T3" , NULL}, + {"T4" , (getter)JitCpu_get_T4 , (setter)JitCpu_set_T4 , "T4" , NULL}, + {"T5" , (getter)JitCpu_get_T5 , (setter)JitCpu_set_T5 , "T5" , NULL}, + {"T6" , (getter)JitCpu_get_T6 , (setter)JitCpu_set_T6 , "T6" , NULL}, + {"T7" , (getter)JitCpu_get_T7 , (setter)JitCpu_set_T7 , "T7" , NULL}, + {"S0" , (getter)JitCpu_get_S0 , (setter)JitCpu_set_S0 , "S0" , NULL}, + {"S1" , (getter)JitCpu_get_S1 , (setter)JitCpu_set_S1 , "S1" , NULL}, + {"S2" , (getter)JitCpu_get_S2 , (setter)JitCpu_set_S2 , "S2" , NULL}, + {"S3" , (getter)JitCpu_get_S3 , (setter)JitCpu_set_S3 , "S3" , NULL}, + {"S4" , (getter)JitCpu_get_S4 , (setter)JitCpu_set_S4 , "S4" , NULL}, + {"S5" , (getter)JitCpu_get_S5 , (setter)JitCpu_set_S5 , "S5" , NULL}, + {"S6" , (getter)JitCpu_get_S6 , (setter)JitCpu_set_S6 , "S6" , NULL}, + {"S7" , (getter)JitCpu_get_S7 , (setter)JitCpu_set_S7 , "S7" , NULL}, + {"T8" , (getter)JitCpu_get_T8 , (setter)JitCpu_set_T8 , "T8" , NULL}, + {"T9" , (getter)JitCpu_get_T9 , (setter)JitCpu_set_T9 , "T9" , NULL}, + {"K0" , (getter)JitCpu_get_K0 , (setter)JitCpu_set_K0 , "K0" , NULL}, + {"K1" , (getter)JitCpu_get_K1 , (setter)JitCpu_set_K1 , "K1" , NULL}, + {"GP" , (getter)JitCpu_get_GP , (setter)JitCpu_set_GP , "GP" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + {"FP" , (getter)JitCpu_get_FP , (setter)JitCpu_set_FP , "FP" , NULL}, + {"RA" , (getter)JitCpu_get_RA , (setter)JitCpu_set_RA , "RA" , NULL}, + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + {"PC_FETCH" , (getter)JitCpu_get_PC_FETCH , (setter)JitCpu_set_PC_FETCH , "PC_FETCH" , NULL}, + {"R_LO" , (getter)JitCpu_get_R_LO , (setter)JitCpu_set_R_LO , "R_LO" , NULL}, + {"R_HI" , (getter)JitCpu_get_R_HI , (setter)JitCpu_set_R_HI , "R_HI" , NULL}, + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_mips32.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_mips32_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + + + +MOD_INIT(JitCore_mips32) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_mips32", "JitCore_mips32 module", JitCore_mips32_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} diff --git a/src/miasm/jitter/arch/JitCore_mips32.h b/src/miasm/jitter/arch/JitCore_mips32.h new file mode 100644 index 00000000..8478fb53 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_mips32.h @@ -0,0 +1,343 @@ + +struct vm_cpu { + uint32_t exception_flags; + + /* gpregs */ + + uint32_t ZERO; + uint32_t AT; + uint32_t V0; + uint32_t V1; + uint32_t A0; + uint32_t A1; + uint32_t A2; + uint32_t A3; + uint32_t T0; + uint32_t T1; + uint32_t T2; + uint32_t T3; + uint32_t T4; + uint32_t T5; + uint32_t T6; + uint32_t T7; + uint32_t S0; + uint32_t S1; + uint32_t S2; + uint32_t S3; + uint32_t S4; + uint32_t S5; + uint32_t S6; + uint32_t S7; + uint32_t T8; + uint32_t T9; + uint32_t K0; + uint32_t K1; + uint32_t GP; + uint32_t SP; + uint32_t FP; + uint32_t RA; + uint32_t PC; + uint32_t PC_FETCH; + uint32_t R_LO; + uint32_t R_HI; + + + double F0; + double F1; + double F2; + double F3; + double F4; + double F5; + double F6; + double F7; + double F8; + double F9; + double F10; + double F11; + double F12; + double F13; + double F14; + double F15; + double F16; + double F17; + double F18; + double F19; + double F20; + double F21; + double F22; + double F23; + double F24; + double F25; + double F26; + double F27; + double F28; + double F29; + double F30; + double F31; + + uint32_t INDEX; + uint32_t CPR0_1; + uint32_t CPR0_2; + uint32_t CPR0_3; + uint32_t CPR0_4; + uint32_t CPR0_5; + uint32_t CPR0_6; + uint32_t CPR0_7; + uint32_t RANDOM; + uint32_t CPR0_9; + uint32_t CPR0_10; + uint32_t CPR0_11; + uint32_t CPR0_12; + uint32_t CPR0_13; + uint32_t CPR0_14; + uint32_t CPR0_15; + uint32_t ENTRYLO0; + uint32_t CPR0_17; + uint32_t CPR0_18; + uint32_t CPR0_19; + uint32_t CPR0_20; + uint32_t CPR0_21; + uint32_t CPR0_22; + uint32_t CPR0_23; + uint32_t ENTRYLO1; + uint32_t CPR0_25; + uint32_t CPR0_26; + uint32_t CPR0_27; + uint32_t CPR0_28; + uint32_t CPR0_29; + uint32_t CPR0_30; + uint32_t CPR0_31; + uint32_t CONTEXT; + uint32_t CONTEXTCONFIG; + uint32_t CPR0_34; + uint32_t CPR0_35; + uint32_t CPR0_36; + uint32_t CPR0_37; + uint32_t CPR0_38; + uint32_t CPR0_39; + uint32_t PAGEMASK; + uint32_t PAGEGRAIN; + uint32_t SEGCTL0; + uint32_t SEGCTL1; + uint32_t SEGCTL2; + uint32_t PWBASE; + uint32_t PWFIELD; + uint32_t PWSIZE; + uint32_t WIRED; + uint32_t CPR0_49; + uint32_t CPR0_50; + uint32_t CPR0_51; + uint32_t CPR0_52; + uint32_t CPR0_53; + uint32_t PWCTL; + uint32_t CPR0_55; + uint32_t CPR0_56; + uint32_t CPR0_57; + uint32_t CPR0_58; + uint32_t CPR0_59; + uint32_t CPR0_60; + uint32_t CPR0_61; + uint32_t CPR0_62; + uint32_t CPR0_63; + uint32_t BADVADDR; + uint32_t BADINSTR; + uint32_t BADINSTRP; + uint32_t CPR0_67; + uint32_t CPR0_68; + uint32_t CPR0_69; + uint32_t CPR0_70; + uint32_t CPR0_71; + uint32_t COUNT; + uint32_t CPR0_73; + uint32_t CPR0_74; + uint32_t CPR0_75; + uint32_t CPR0_76; + uint32_t CPR0_77; + uint32_t CPR0_78; + uint32_t CPR0_79; + uint32_t ENTRYHI; + uint32_t CPR0_81; + uint32_t CPR0_82; + uint32_t CPR0_83; + uint32_t CPR0_84; + uint32_t CPR0_85; + uint32_t CPR0_86; + uint32_t CPR0_87; + uint32_t CPR0_88; + uint32_t CPR0_89; + uint32_t CPR0_90; + uint32_t CPR0_91; + uint32_t CPR0_92; + uint32_t CPR0_93; + uint32_t CPR0_94; + uint32_t CPR0_95; + uint32_t CPR0_96; + uint32_t CPR0_97; + uint32_t CPR0_98; + uint32_t CPR0_99; + uint32_t CPR0_100; + uint32_t CPR0_101; + uint32_t CPR0_102; + uint32_t CPR0_103; + uint32_t CAUSE; + uint32_t CPR0_105; + uint32_t CPR0_106; + uint32_t CPR0_107; + uint32_t CPR0_108; + uint32_t CPR0_109; + uint32_t CPR0_110; + uint32_t CPR0_111; + uint32_t EPC; + uint32_t CPR0_113; + uint32_t CPR0_114; + uint32_t CPR0_115; + uint32_t CPR0_116; + uint32_t CPR0_117; + uint32_t CPR0_118; + uint32_t CPR0_119; + uint32_t PRID; + uint32_t EBASE; + uint32_t CPR0_122; + uint32_t CPR0_123; + uint32_t CPR0_124; + uint32_t CPR0_125; + uint32_t CPR0_126; + uint32_t CPR0_127; + uint32_t CONFIG; + uint32_t CONFIG1; + uint32_t CONFIG2; + uint32_t CONFIG3; + uint32_t CONFIG4; + uint32_t CONFIG5; + uint32_t CPR0_134; + uint32_t CPR0_135; + uint32_t CPR0_136; + uint32_t CPR0_137; + uint32_t CPR0_138; + uint32_t CPR0_139; + uint32_t CPR0_140; + uint32_t CPR0_141; + uint32_t CPR0_142; + uint32_t CPR0_143; + uint32_t CPR0_144; + uint32_t CPR0_145; + uint32_t CPR0_146; + uint32_t CPR0_147; + uint32_t CPR0_148; + uint32_t CPR0_149; + uint32_t CPR0_150; + uint32_t CPR0_151; + uint32_t WATCHHI; + uint32_t CPR0_153; + uint32_t CPR0_154; + uint32_t CPR0_155; + uint32_t CPR0_156; + uint32_t CPR0_157; + uint32_t CPR0_158; + uint32_t CPR0_159; + uint32_t CPR0_160; + uint32_t CPR0_161; + uint32_t CPR0_162; + uint32_t CPR0_163; + uint32_t CPR0_164; + uint32_t CPR0_165; + uint32_t CPR0_166; + uint32_t CPR0_167; + uint32_t CPR0_168; + uint32_t CPR0_169; + uint32_t CPR0_170; + uint32_t CPR0_171; + uint32_t CPR0_172; + uint32_t CPR0_173; + uint32_t CPR0_174; + uint32_t CPR0_175; + uint32_t CPR0_176; + uint32_t CPR0_177; + uint32_t CPR0_178; + uint32_t CPR0_179; + uint32_t CPR0_180; + uint32_t CPR0_181; + uint32_t CPR0_182; + uint32_t CPR0_183; + uint32_t CPR0_184; + uint32_t CPR0_185; + uint32_t CPR0_186; + uint32_t CPR0_187; + uint32_t CPR0_188; + uint32_t CPR0_189; + uint32_t CPR0_190; + uint32_t CPR0_191; + uint32_t CPR0_192; + uint32_t CPR0_193; + uint32_t CPR0_194; + uint32_t CPR0_195; + uint32_t CPR0_196; + uint32_t CPR0_197; + uint32_t CPR0_198; + uint32_t CPR0_199; + uint32_t CPR0_200; + uint32_t CPR0_201; + uint32_t CPR0_202; + uint32_t CPR0_203; + uint32_t CPR0_204; + uint32_t CPR0_205; + uint32_t CPR0_206; + uint32_t CPR0_207; + uint32_t CPR0_208; + uint32_t CPR0_209; + uint32_t CPR0_210; + uint32_t CPR0_211; + uint32_t CPR0_212; + uint32_t CPR0_213; + uint32_t CPR0_214; + uint32_t CPR0_215; + uint32_t CPR0_216; + uint32_t CPR0_217; + uint32_t CPR0_218; + uint32_t CPR0_219; + uint32_t CPR0_220; + uint32_t CPR0_221; + uint32_t CPR0_222; + uint32_t CPR0_223; + uint32_t CPR0_224; + uint32_t CPR0_225; + uint32_t CPR0_226; + uint32_t CPR0_227; + uint32_t CPR0_228; + uint32_t CPR0_229; + uint32_t CPR0_230; + uint32_t CPR0_231; + uint32_t CPR0_232; + uint32_t CPR0_233; + uint32_t CPR0_234; + uint32_t CPR0_235; + uint32_t CPR0_236; + uint32_t CPR0_237; + uint32_t CPR0_238; + uint32_t CPR0_239; + uint32_t CPR0_240; + uint32_t CPR0_241; + uint32_t CPR0_242; + uint32_t CPR0_243; + uint32_t CPR0_244; + uint32_t CPR0_245; + uint32_t CPR0_246; + uint32_t CPR0_247; + uint32_t CPR0_248; + uint32_t CPR0_249; + uint32_t KSCRATCH0; + uint32_t KSCRATCH1; + uint32_t KSCRATCH2; + uint32_t KSCRATCH3; + uint32_t KSCRATCH4; + uint32_t KSCRATCH5; +}; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/JitCore_msp430.c b/src/miasm/jitter/arch/JitCore_msp430.c new file mode 100644 index 00000000..86e082ad --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_msp430.c @@ -0,0 +1,423 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "JitCore_msp430.h" + + +reg_dict gpreg_dict[] = { {.name = "PC", .offset = offsetof(struct vm_cpu, PC)}, + {.name = "SP", .offset = offsetof(struct vm_cpu, SP)}, + //{.name = "SR", .offset = offsetof(struct vm_cpu, SR)}, + {.name = "R3", .offset = offsetof(struct vm_cpu, R3)}, + {.name = "R4", .offset = offsetof(struct vm_cpu, R4)}, + {.name = "R5", .offset = offsetof(struct vm_cpu, R5)}, + {.name = "R6", .offset = offsetof(struct vm_cpu, R6)}, + {.name = "R7", .offset = offsetof(struct vm_cpu, R7)}, + {.name = "R8", .offset = offsetof(struct vm_cpu, R8)}, + {.name = "R9", .offset = offsetof(struct vm_cpu, R9)}, + {.name = "R10", .offset = offsetof(struct vm_cpu, R10)}, + {.name = "R11", .offset = offsetof(struct vm_cpu, R11)}, + {.name = "R12", .offset = offsetof(struct vm_cpu, R12)}, + {.name = "R13", .offset = offsetof(struct vm_cpu, R13)}, + {.name = "R14", .offset = offsetof(struct vm_cpu, R14)}, + {.name = "R15", .offset = offsetof(struct vm_cpu, R15)}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf)}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf)}, + {.name = "of", .offset = offsetof(struct vm_cpu, of)}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf)}, + + {.name = "cpuoff", .offset = offsetof(struct vm_cpu, cpuoff)}, + {.name = "gie", .offset = offsetof(struct vm_cpu, gie)}, + {.name = "osc", .offset = offsetof(struct vm_cpu, osc)}, + {.name = "scg0", .offset = offsetof(struct vm_cpu, scg0)}, + {.name = "scg1", .offset = offsetof(struct vm_cpu, scg1)}, + {.name = "res", .offset = offsetof(struct vm_cpu, res)}, + +}; + +/************************** JitCpu object **************************/ + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(PC); + get_reg(SP); + //get_reg(SR); + get_reg(R3); + get_reg(R4); + get_reg(R5); + get_reg(R6); + get_reg(R7); + get_reg(R8); + get_reg(R9); + get_reg(R10); + get_reg(R11); + get_reg(R12); + get_reg(R13); + get_reg(R14); + get_reg(R15); + + get_reg(zf); + get_reg(nf); + get_reg(of); + get_reg(cf); + + get_reg(cpuoff); + get_reg(gie); + get_reg(osc); + get_reg(scg0); + get_reg(scg1); + get_reg(res); + + + return dict; +} + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + + + + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; + +} + +void dump_gpregs(struct vm_cpu* vmcpu) +{ + + printf("PC %.4"PRIX32" SP %.4"PRIX32" R3 %.4"PRIX32" ", + vmcpu->PC, vmcpu->SP, vmcpu->R3); + printf("R4 %.4"PRIX32" R5 %.4"PRIX32" R6 %.4"PRIX32" R7 %.4"PRIX32"\n", + vmcpu->R4, vmcpu->R5, vmcpu->R6, vmcpu->R7); + printf("R8 %.4"PRIX32" R9 %.4"PRIX32" R10 %.4"PRIX32" R11 %.4"PRIX32" ", + vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11); + printf("R12 %.4"PRIX32" R13 %.4"PRIX32" R14 %.4"PRIX32" R15 %.4"PRIX32"\n", + vmcpu->R12, vmcpu->R13, vmcpu->R14, vmcpu->R15); + printf("zf %"PRIX32" nf %"PRIX32" of %"PRIX32" cf %"PRIX32"\n", + vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf); +} + + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +getset_reg_u16(PC); +getset_reg_u16(SP); +getset_reg_u16(R3); +getset_reg_u16(R4); +getset_reg_u16(R5); +getset_reg_u16(R6); +getset_reg_u16(R7); +getset_reg_u16(R8); +getset_reg_u16(R9); +getset_reg_u16(R10); +getset_reg_u16(R11); +getset_reg_u16(R12); +getset_reg_u16(R13); +getset_reg_u16(R14); +getset_reg_u16(R15); +getset_reg_u16(zf); +getset_reg_u16(nf); +getset_reg_u16(of); +getset_reg_u16(cf); +getset_reg_u16(cpuoff); +getset_reg_u16(gie); +getset_reg_u16(osc); +getset_reg_u16(scg0); +getset_reg_u16(scg1); +getset_reg_u16(res); + + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + get_reg_off(exception_flags); + + get_reg_off(PC); + get_reg_off(SP); + get_reg_off(R3); + get_reg_off(R4); + get_reg_off(R5); + get_reg_off(R6); + get_reg_off(R7); + get_reg_off(R8); + get_reg_off(R9); + get_reg_off(R10); + get_reg_off(R11); + get_reg_off(R12); + get_reg_off(R13); + get_reg_off(R14); + get_reg_off(R15); + + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(of); + get_reg_off(cf); + get_reg_off(cpuoff); + get_reg_off(gie); + get_reg_off(osc); + get_reg_off(scg0); + get_reg_off(scg1); + get_reg_off(res); + + return dict; +} + + + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + {"PC" , (getter)JitCpu_get_PC , (setter)JitCpu_set_PC , "PC" , NULL}, + {"SP" , (getter)JitCpu_get_SP , (setter)JitCpu_set_SP , "SP" , NULL}, + {"R3" , (getter)JitCpu_get_R3 , (setter)JitCpu_set_R3 , "R3" , NULL}, + {"R4" , (getter)JitCpu_get_R4 , (setter)JitCpu_set_R4 , "R4" , NULL}, + {"R5" , (getter)JitCpu_get_R5 , (setter)JitCpu_set_R5 , "R5" , NULL}, + {"R6" , (getter)JitCpu_get_R6 , (setter)JitCpu_set_R6 , "R6" , NULL}, + {"R7" , (getter)JitCpu_get_R7 , (setter)JitCpu_set_R7 , "R7" , NULL}, + {"R8" , (getter)JitCpu_get_R8 , (setter)JitCpu_set_R8 , "R8" , NULL}, + {"R9" , (getter)JitCpu_get_R9 , (setter)JitCpu_set_R9 , "R9" , NULL}, + {"R10" , (getter)JitCpu_get_R10 , (setter)JitCpu_set_R10 , "R10" , NULL}, + {"R11" , (getter)JitCpu_get_R11 , (setter)JitCpu_set_R11 , "R11" , NULL}, + {"R12" , (getter)JitCpu_get_R12 , (setter)JitCpu_set_R12 , "R12" , NULL}, + {"R13" , (getter)JitCpu_get_R13 , (setter)JitCpu_set_R13 , "R13" , NULL}, + {"R14" , (getter)JitCpu_get_R14 , (setter)JitCpu_set_R14 , "R14" , NULL}, + {"R15" , (getter)JitCpu_get_R15 , (setter)JitCpu_set_R15 , "R15" , NULL}, + {"zf" , (getter)JitCpu_get_zf , (setter)JitCpu_set_zf , "zf" , NULL}, + {"nf" , (getter)JitCpu_get_nf , (setter)JitCpu_set_nf , "nf" , NULL}, + {"of" , (getter)JitCpu_get_of , (setter)JitCpu_set_of , "of" , NULL}, + {"cf" , (getter)JitCpu_get_cf , (setter)JitCpu_set_cf , "cf" , NULL}, + {"cpuoff" , (getter)JitCpu_get_cpuoff , (setter)JitCpu_set_cpuoff , "cpuoff" , NULL}, + {"gie" , (getter)JitCpu_get_gie , (setter)JitCpu_set_gie , "gie" , NULL}, + {"osc" , (getter)JitCpu_get_osc , (setter)JitCpu_set_osc , "osc" , NULL}, + {"scg0" , (getter)JitCpu_get_scg0 , (setter)JitCpu_set_scg0 , "scg0" , NULL}, + {"scg1" , (getter)JitCpu_get_scg1 , (setter)JitCpu_set_scg1 , "scg1" , NULL}, + {"res" , (getter)JitCpu_get_res , (setter)JitCpu_set_res , "res" , NULL}, + + {NULL} /* Sentinel */ +}; + + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_msp430.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_msp430_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + + + +MOD_INIT(JitCore_msp430) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_msp430", "JitCore_msp430 module", JitCore_msp430_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} diff --git a/src/miasm/jitter/arch/JitCore_msp430.h b/src/miasm/jitter/arch/JitCore_msp430.h new file mode 100644 index 00000000..d7b6a7b9 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_msp430.h @@ -0,0 +1,44 @@ + +struct vm_cpu { + uint32_t exception_flags; + + /* gpregs */ + uint32_t PC; + uint32_t SP; + uint32_t R3; + uint32_t R4; + uint32_t R5; + uint32_t R6; + uint32_t R7; + uint32_t R8; + uint32_t R9; + uint32_t R10; + uint32_t R11; + uint32_t R12; + uint32_t R13; + uint32_t R14; + uint32_t R15; + + /* eflag */ + uint32_t zf; + uint32_t nf; + uint32_t of; + uint32_t cf; + + uint32_t cpuoff; + uint32_t gie; + uint32_t osc; + uint32_t scg0; + uint32_t scg1; + uint32_t res; + +}; + +#define RETURN_PC return BlockDst; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu* vmcpu); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); diff --git a/src/miasm/jitter/arch/JitCore_ppc32.c b/src/miasm/jitter/arch/JitCore_ppc32.c new file mode 100644 index 00000000..086b140f --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_ppc32.c @@ -0,0 +1,297 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "JitCore_ppc32.h" + +reg_dict gpreg_dict[] = { +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + { .name = #_name, .offset = offsetof(struct vm_cpu, _name), .size = _size }, +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND +}; + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + get_reg(_name); +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + + return dict; +} + + + +PyObject * +cpu_set_gpreg(JitCpu *self, PyObject *args) { + PyObject *dict; + PyObject *d_key, *d_value = NULL; + Py_ssize_t pos = 0; + const char *d_key_name; + uint32_t val; + unsigned int i; + + if (!PyArg_ParseTuple(args, "O", &dict)) + return NULL; + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + + while(PyDict_Next(dict, &pos, &d_key, &d_value)) { + int found = 0; + PyGetStr(d_key_name, d_key); + PyGetInt_uint32_t(d_value, val); + + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val; + found = 1; + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * +cpu_init_regs(JitCpu *self) { + memset(self->cpu, 0, sizeof(struct vm_cpu)); + + Py_INCREF(Py_None); + return Py_None; +} + +static void +dump_gpreg(const char *name, uint32_t val, int *n) { + printf("%6s %.8" PRIX32"%c", name, val, (*n + 1) % 4 == 0? '\n':' '); + *n = (*n + 1) % 4; +} + +void +dump_gpregs(struct vm_cpu *vmcpu) { + int reg_num = 0; + +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + dump_gpreg(#_name, vmcpu->_name, ®_num); +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + + if ((reg_num % 4) != 0) + putchar('\n'); +} + + +PyObject * +cpu_dump_gpregs(JitCpu *self, PyObject *args) { + + dump_gpregs(self->cpu); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * +cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + return cpu_dump_gpregs(self, args); +} + +PyObject * +cpu_set_exception(JitCpu *self, PyObject *args) { + PyObject *item1; + uint64_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + return NULL; + + PyGetInt_uint64_t(item1, exception_flags); + + ((struct vm_cpu *)self->cpu)->exception_flags = exception_flags; + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * +cpu_get_exception(JitCpu *self, PyObject *args) { + return PyLong_FromUnsignedLongLong(((struct vm_cpu *)self->cpu)->exception_flags); +} + +static PyObject * +cpu_get_spr_access(JitCpu *self, PyObject *args) { + return PyLong_FromUnsignedLongLong(((struct vm_cpu *) self->cpu)->spr_access); +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, "X"}, + {"get_spr_access", (PyCFunction)cpu_get_spr_access, METH_VARARGS, "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) { + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(1); + } + return 0; +} + + +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ +getset_reg_u32(_name); +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + +PyObject * +get_gpreg_offset_all(void) { + PyObject *dict = PyDict_New(); + PyObject *o; + +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + get_reg_off(_name); +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + + return dict; +} + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + { #_name, (getter) JitCpu_get_ ## _name , \ + (setter) JitCpu_set_ ## _name , #_name , NULL}, +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_ppc.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_ppc32_Methods[] = { + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + + +MOD_INIT(JitCore_ppc32) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_ppc32", "JitCore_ppc32 module", JitCore_ppc32_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} diff --git a/src/miasm/jitter/arch/JitCore_ppc32.h b/src/miasm/jitter/arch/JitCore_ppc32.h new file mode 100644 index 00000000..abb04941 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_ppc32.h @@ -0,0 +1,22 @@ +/* + * _size can't be used yet because all register accesses are homogeneously + * 32-bit + */ +struct vm_cpu { +#define JITCORE_PPC_REG_EXPAND(_name, _size) \ + uint32_t _name; +#include "JitCore_ppc32_regs.h" +#undef JITCORE_PPC_REG_EXPAND + + uint64_t exception_flags; + uint32_t spr_access; + uint32_t reserve; + uint32_t reserve_address; +}; + +_MIASM_EXPORT void dump_gpregs(struct vm_cpu *); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); diff --git a/src/miasm/jitter/arch/JitCore_ppc32_regs.h b/src/miasm/jitter/arch/JitCore_ppc32_regs.h new file mode 100644 index 00000000..79191d32 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_ppc32_regs.h @@ -0,0 +1,192 @@ +JITCORE_PPC_REG_EXPAND(R0, 32) +JITCORE_PPC_REG_EXPAND(R1, 32) +JITCORE_PPC_REG_EXPAND(R2, 32) +JITCORE_PPC_REG_EXPAND(R3, 32) +JITCORE_PPC_REG_EXPAND(R4, 32) +JITCORE_PPC_REG_EXPAND(R5, 32) +JITCORE_PPC_REG_EXPAND(R6, 32) +JITCORE_PPC_REG_EXPAND(R7, 32) +JITCORE_PPC_REG_EXPAND(R8, 32) +JITCORE_PPC_REG_EXPAND(R9, 32) +JITCORE_PPC_REG_EXPAND(R10, 32) +JITCORE_PPC_REG_EXPAND(R11, 32) +JITCORE_PPC_REG_EXPAND(R12, 32) +JITCORE_PPC_REG_EXPAND(R13, 32) +JITCORE_PPC_REG_EXPAND(R14, 32) +JITCORE_PPC_REG_EXPAND(R15, 32) +JITCORE_PPC_REG_EXPAND(R16, 32) +JITCORE_PPC_REG_EXPAND(R17, 32) +JITCORE_PPC_REG_EXPAND(R18, 32) +JITCORE_PPC_REG_EXPAND(R19, 32) +JITCORE_PPC_REG_EXPAND(R20, 32) +JITCORE_PPC_REG_EXPAND(R21, 32) +JITCORE_PPC_REG_EXPAND(R22, 32) +JITCORE_PPC_REG_EXPAND(R23, 32) +JITCORE_PPC_REG_EXPAND(R24, 32) +JITCORE_PPC_REG_EXPAND(R25, 32) +JITCORE_PPC_REG_EXPAND(R26, 32) +JITCORE_PPC_REG_EXPAND(R27, 32) +JITCORE_PPC_REG_EXPAND(R28, 32) +JITCORE_PPC_REG_EXPAND(R29, 32) +JITCORE_PPC_REG_EXPAND(R30, 32) +JITCORE_PPC_REG_EXPAND(R31, 32) + +JITCORE_PPC_REG_EXPAND(PC, 32) +JITCORE_PPC_REG_EXPAND(LR, 32) +JITCORE_PPC_REG_EXPAND(CTR, 32) +JITCORE_PPC_REG_EXPAND(MSR, 32) + +JITCORE_PPC_REG_EXPAND(XER_SO, 32) +JITCORE_PPC_REG_EXPAND(XER_OV, 32) +JITCORE_PPC_REG_EXPAND(XER_CA, 32) +JITCORE_PPC_REG_EXPAND(XER_BC, 32) + +JITCORE_PPC_REG_EXPAND(CR0_LT, 8) +JITCORE_PPC_REG_EXPAND(CR0_GT, 8) +JITCORE_PPC_REG_EXPAND(CR0_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR0_SO, 8) +JITCORE_PPC_REG_EXPAND(CR1_LT, 8) +JITCORE_PPC_REG_EXPAND(CR1_GT, 8) +JITCORE_PPC_REG_EXPAND(CR1_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR1_SO, 8) +JITCORE_PPC_REG_EXPAND(CR2_LT, 8) +JITCORE_PPC_REG_EXPAND(CR2_GT, 8) +JITCORE_PPC_REG_EXPAND(CR2_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR2_SO, 8) +JITCORE_PPC_REG_EXPAND(CR3_LT, 8) +JITCORE_PPC_REG_EXPAND(CR3_GT, 8) +JITCORE_PPC_REG_EXPAND(CR3_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR3_SO, 8) +JITCORE_PPC_REG_EXPAND(CR4_LT, 8) +JITCORE_PPC_REG_EXPAND(CR4_GT, 8) +JITCORE_PPC_REG_EXPAND(CR4_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR4_SO, 8) +JITCORE_PPC_REG_EXPAND(CR5_LT, 8) +JITCORE_PPC_REG_EXPAND(CR5_GT, 8) +JITCORE_PPC_REG_EXPAND(CR5_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR5_SO, 8) +JITCORE_PPC_REG_EXPAND(CR6_LT, 8) +JITCORE_PPC_REG_EXPAND(CR6_GT, 8) +JITCORE_PPC_REG_EXPAND(CR6_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR6_SO, 8) +JITCORE_PPC_REG_EXPAND(CR7_LT, 8) +JITCORE_PPC_REG_EXPAND(CR7_GT, 8) +JITCORE_PPC_REG_EXPAND(CR7_EQ, 8) +JITCORE_PPC_REG_EXPAND(CR7_SO, 8) + +JITCORE_PPC_REG_EXPAND(SPRG0, 32) +JITCORE_PPC_REG_EXPAND(SPRG1, 32) +JITCORE_PPC_REG_EXPAND(SPRG2, 32) +JITCORE_PPC_REG_EXPAND(SPRG3, 32) +JITCORE_PPC_REG_EXPAND(SRR0, 32) +JITCORE_PPC_REG_EXPAND(SRR1, 32) +JITCORE_PPC_REG_EXPAND(DAR, 32) +JITCORE_PPC_REG_EXPAND(DSISR, 32) +JITCORE_PPC_REG_EXPAND(PIR, 32) +JITCORE_PPC_REG_EXPAND(PVR, 32) +JITCORE_PPC_REG_EXPAND(DEC, 32) +JITCORE_PPC_REG_EXPAND(TBL, 32) +JITCORE_PPC_REG_EXPAND(TBU, 32) + +JITCORE_PPC_REG_EXPAND(SR0, 32) +JITCORE_PPC_REG_EXPAND(SR1, 32) +JITCORE_PPC_REG_EXPAND(SR2, 32) +JITCORE_PPC_REG_EXPAND(SR3, 32) +JITCORE_PPC_REG_EXPAND(SR4, 32) +JITCORE_PPC_REG_EXPAND(SR5, 32) +JITCORE_PPC_REG_EXPAND(SR6, 32) +JITCORE_PPC_REG_EXPAND(SR7, 32) +JITCORE_PPC_REG_EXPAND(SR8, 32) +JITCORE_PPC_REG_EXPAND(SR9, 32) +JITCORE_PPC_REG_EXPAND(SR10, 32) +JITCORE_PPC_REG_EXPAND(SR11, 32) +JITCORE_PPC_REG_EXPAND(SR12, 32) +JITCORE_PPC_REG_EXPAND(SR13, 32) +JITCORE_PPC_REG_EXPAND(SR14, 32) +JITCORE_PPC_REG_EXPAND(SR15, 32) +JITCORE_PPC_REG_EXPAND(IBAT0U, 32) +JITCORE_PPC_REG_EXPAND(IBAT0L, 32) +JITCORE_PPC_REG_EXPAND(IBAT1U, 32) +JITCORE_PPC_REG_EXPAND(IBAT1L, 32) +JITCORE_PPC_REG_EXPAND(IBAT2U, 32) +JITCORE_PPC_REG_EXPAND(IBAT2L, 32) +JITCORE_PPC_REG_EXPAND(IBAT3U, 32) +JITCORE_PPC_REG_EXPAND(IBAT3L, 32) +JITCORE_PPC_REG_EXPAND(DBAT0U, 32) +JITCORE_PPC_REG_EXPAND(DBAT0L, 32) +JITCORE_PPC_REG_EXPAND(DBAT1U, 32) +JITCORE_PPC_REG_EXPAND(DBAT1L, 32) +JITCORE_PPC_REG_EXPAND(DBAT2U, 32) +JITCORE_PPC_REG_EXPAND(DBAT2L, 32) +JITCORE_PPC_REG_EXPAND(DBAT3U, 32) +JITCORE_PPC_REG_EXPAND(DBAT3L, 32) +JITCORE_PPC_REG_EXPAND(SDR1, 32) + +JITCORE_PPC_REG_EXPAND(FPR0, 64) +JITCORE_PPC_REG_EXPAND(FPR1, 64) +JITCORE_PPC_REG_EXPAND(FPR2, 64) +JITCORE_PPC_REG_EXPAND(FPR3, 64) +JITCORE_PPC_REG_EXPAND(FPR4, 64) +JITCORE_PPC_REG_EXPAND(FPR5, 64) +JITCORE_PPC_REG_EXPAND(FPR6, 64) +JITCORE_PPC_REG_EXPAND(FPR7, 64) +JITCORE_PPC_REG_EXPAND(FPR8, 64) +JITCORE_PPC_REG_EXPAND(FPR9, 64) +JITCORE_PPC_REG_EXPAND(FPR10, 64) +JITCORE_PPC_REG_EXPAND(FPR11, 64) +JITCORE_PPC_REG_EXPAND(FPR12, 64) +JITCORE_PPC_REG_EXPAND(FPR13, 64) +JITCORE_PPC_REG_EXPAND(FPR14, 64) +JITCORE_PPC_REG_EXPAND(FPR15, 64) +JITCORE_PPC_REG_EXPAND(FPR16, 64) +JITCORE_PPC_REG_EXPAND(FPR17, 64) +JITCORE_PPC_REG_EXPAND(FPR18, 64) +JITCORE_PPC_REG_EXPAND(FPR19, 64) +JITCORE_PPC_REG_EXPAND(FPR20, 64) +JITCORE_PPC_REG_EXPAND(FPR21, 64) +JITCORE_PPC_REG_EXPAND(FPR22, 64) +JITCORE_PPC_REG_EXPAND(FPR23, 64) +JITCORE_PPC_REG_EXPAND(FPR24, 64) +JITCORE_PPC_REG_EXPAND(FPR25, 64) +JITCORE_PPC_REG_EXPAND(FPR26, 64) +JITCORE_PPC_REG_EXPAND(FPR27, 64) +JITCORE_PPC_REG_EXPAND(FPR28, 64) +JITCORE_PPC_REG_EXPAND(FPR29, 64) +JITCORE_PPC_REG_EXPAND(FPR30, 64) +JITCORE_PPC_REG_EXPAND(FPR31, 64) +JITCORE_PPC_REG_EXPAND(FPSCR, 32) + +JITCORE_PPC_REG_EXPAND(VR0, 128) +JITCORE_PPC_REG_EXPAND(VR1, 128) +JITCORE_PPC_REG_EXPAND(VR2, 128) +JITCORE_PPC_REG_EXPAND(VR3, 128) +JITCORE_PPC_REG_EXPAND(VR4, 128) +JITCORE_PPC_REG_EXPAND(VR5, 128) +JITCORE_PPC_REG_EXPAND(VR6, 128) +JITCORE_PPC_REG_EXPAND(VR7, 128) +JITCORE_PPC_REG_EXPAND(VR8, 128) +JITCORE_PPC_REG_EXPAND(VR9, 128) +JITCORE_PPC_REG_EXPAND(VR10, 128) +JITCORE_PPC_REG_EXPAND(VR11, 128) +JITCORE_PPC_REG_EXPAND(VR12, 128) +JITCORE_PPC_REG_EXPAND(VR13, 128) +JITCORE_PPC_REG_EXPAND(VR14, 128) +JITCORE_PPC_REG_EXPAND(VR15, 128) +JITCORE_PPC_REG_EXPAND(VR16, 128) +JITCORE_PPC_REG_EXPAND(VR17, 128) +JITCORE_PPC_REG_EXPAND(VR18, 128) +JITCORE_PPC_REG_EXPAND(VR19, 128) +JITCORE_PPC_REG_EXPAND(VR20, 128) +JITCORE_PPC_REG_EXPAND(VR21, 128) +JITCORE_PPC_REG_EXPAND(VR22, 128) +JITCORE_PPC_REG_EXPAND(VR23, 128) +JITCORE_PPC_REG_EXPAND(VR24, 128) +JITCORE_PPC_REG_EXPAND(VR25, 128) +JITCORE_PPC_REG_EXPAND(VR26, 128) +JITCORE_PPC_REG_EXPAND(VR27, 128) +JITCORE_PPC_REG_EXPAND(VR28, 128) +JITCORE_PPC_REG_EXPAND(VR29, 128) +JITCORE_PPC_REG_EXPAND(VR30, 128) +JITCORE_PPC_REG_EXPAND(VR31, 128) +JITCORE_PPC_REG_EXPAND(VRSAVE, 32) +JITCORE_PPC_REG_EXPAND(VSCR, 32) diff --git a/src/miasm/jitter/arch/JitCore_x86.c b/src/miasm/jitter/arch/JitCore_x86.c new file mode 100644 index 00000000..9081f3d8 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_x86.c @@ -0,0 +1,903 @@ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include "../compat_py23.h" +#include "../queue.h" +#include "../vm_mngr.h" +#include "../bn.h" +#include "../vm_mngr_py.h" +#include "../JitCore.h" +#include "../op_semantics.h" +#include "JitCore_x86.h" + + +struct vm_cpu ref_arch_regs; + +reg_dict gpreg_dict[] = { + {.name = "RAX", .offset = offsetof(struct vm_cpu, RAX), .size = 64}, + {.name = "RBX", .offset = offsetof(struct vm_cpu, RBX), .size = 64}, + {.name = "RCX", .offset = offsetof(struct vm_cpu, RCX), .size = 64}, + {.name = "RDX", .offset = offsetof(struct vm_cpu, RDX), .size = 64}, + {.name = "RSI", .offset = offsetof(struct vm_cpu, RSI), .size = 64}, + {.name = "RDI", .offset = offsetof(struct vm_cpu, RDI), .size = 64}, + {.name = "RSP", .offset = offsetof(struct vm_cpu, RSP), .size = 64}, + {.name = "RBP", .offset = offsetof(struct vm_cpu, RBP), .size = 64}, + + {.name = "R8", .offset = offsetof(struct vm_cpu, R8), .size = 64}, + {.name = "R9", .offset = offsetof(struct vm_cpu, R9), .size = 64}, + {.name = "R10", .offset = offsetof(struct vm_cpu, R10), .size = 64}, + {.name = "R11", .offset = offsetof(struct vm_cpu, R11), .size = 64}, + {.name = "R12", .offset = offsetof(struct vm_cpu, R12), .size = 64}, + {.name = "R13", .offset = offsetof(struct vm_cpu, R13), .size = 64}, + {.name = "R14", .offset = offsetof(struct vm_cpu, R14), .size = 64}, + {.name = "R15", .offset = offsetof(struct vm_cpu, R15), .size = 64}, + + {.name = "RIP", .offset = offsetof(struct vm_cpu, RIP), .size = 64}, + + {.name = "zf", .offset = offsetof(struct vm_cpu, zf), .size = 8}, + {.name = "nf", .offset = offsetof(struct vm_cpu, nf), .size = 8}, + {.name = "pf", .offset = offsetof(struct vm_cpu, pf), .size = 8}, + {.name = "of", .offset = offsetof(struct vm_cpu, of), .size = 8}, + {.name = "cf", .offset = offsetof(struct vm_cpu, cf), .size = 8}, + {.name = "af", .offset = offsetof(struct vm_cpu, af), .size = 8}, + {.name = "df", .offset = offsetof(struct vm_cpu, df), .size = 8}, + + {.name = "ES", .offset = offsetof(struct vm_cpu, ES), .size = 16}, + {.name = "CS", .offset = offsetof(struct vm_cpu, CS), .size = 16}, + {.name = "SS", .offset = offsetof(struct vm_cpu, SS), .size = 16}, + {.name = "DS", .offset = offsetof(struct vm_cpu, DS), .size = 16}, + {.name = "FS", .offset = offsetof(struct vm_cpu, FS), .size = 16}, + {.name = "GS", .offset = offsetof(struct vm_cpu, GS), .size = 16}, + + {.name = "MM0", .offset = offsetof(struct vm_cpu, MM0), .size = 64}, + {.name = "MM1", .offset = offsetof(struct vm_cpu, MM1), .size = 64}, + {.name = "MM2", .offset = offsetof(struct vm_cpu, MM2), .size = 64}, + {.name = "MM3", .offset = offsetof(struct vm_cpu, MM3), .size = 64}, + {.name = "MM4", .offset = offsetof(struct vm_cpu, MM4), .size = 64}, + {.name = "MM5", .offset = offsetof(struct vm_cpu, MM5), .size = 64}, + {.name = "MM6", .offset = offsetof(struct vm_cpu, MM6), .size = 64}, + {.name = "MM7", .offset = offsetof(struct vm_cpu, MM7), .size = 64}, + + {.name = "XMM0", .offset = offsetof(struct vm_cpu, XMM0), .size = 128}, + {.name = "XMM1", .offset = offsetof(struct vm_cpu, XMM1), .size = 128}, + {.name = "XMM2", .offset = offsetof(struct vm_cpu, XMM2), .size = 128}, + {.name = "XMM3", .offset = offsetof(struct vm_cpu, XMM3), .size = 128}, + {.name = "XMM4", .offset = offsetof(struct vm_cpu, XMM4), .size = 128}, + {.name = "XMM5", .offset = offsetof(struct vm_cpu, XMM5), .size = 128}, + {.name = "XMM6", .offset = offsetof(struct vm_cpu, XMM6), .size = 128}, + {.name = "XMM7", .offset = offsetof(struct vm_cpu, XMM7), .size = 128}, + {.name = "XMM8", .offset = offsetof(struct vm_cpu, XMM8), .size = 128}, + {.name = "XMM9", .offset = offsetof(struct vm_cpu, XMM9), .size = 128}, + {.name = "XMM10", .offset = offsetof(struct vm_cpu, XMM10), .size = 128}, + {.name = "XMM11", .offset = offsetof(struct vm_cpu, XMM11), .size = 128}, + {.name = "XMM12", .offset = offsetof(struct vm_cpu, XMM12), .size = 128}, + {.name = "XMM13", .offset = offsetof(struct vm_cpu, XMM13), .size = 128}, + {.name = "XMM14", .offset = offsetof(struct vm_cpu, XMM14), .size = 128}, + {.name = "XMM15", .offset = offsetof(struct vm_cpu, XMM15), .size = 128}, + + {.name = "tsc", .offset = offsetof(struct vm_cpu, tsc), .size = 64}, + + {.name = "exception_flags", .offset = offsetof(struct vm_cpu, exception_flags), .size = 32}, + {.name = "interrupt_num", .offset = offsetof(struct vm_cpu, interrupt_num), .size = 32}, +}; + + + +/************************** JitCpu object **************************/ + + + + + +PyObject* cpu_get_gpreg(JitCpu* self) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + + get_reg(RAX); + get_reg(RBX); + get_reg(RCX); + get_reg(RDX); + get_reg(RSI); + get_reg(RDI); + get_reg(RSP); + get_reg(RBP); + + get_reg(R8); + get_reg(R9); + get_reg(R10); + get_reg(R11); + get_reg(R12); + get_reg(R13); + get_reg(R14); + get_reg(R15); + + get_reg(RIP); + + get_reg(zf); + get_reg(nf); + get_reg(pf); + get_reg(of); + get_reg(cf); + get_reg(af); + get_reg(df); + + + get_reg(ES); + get_reg(CS); + get_reg(SS); + get_reg(DS); + get_reg(FS); + get_reg(GS); + + get_reg(MM0); + get_reg(MM1); + get_reg(MM2); + get_reg(MM3); + get_reg(MM4); + get_reg(MM5); + get_reg(MM6); + get_reg(MM7); + + get_reg_bn(XMM0, 128); + get_reg_bn(XMM1, 128); + get_reg_bn(XMM2, 128); + get_reg_bn(XMM3, 128); + get_reg_bn(XMM4, 128); + get_reg_bn(XMM5, 128); + get_reg_bn(XMM6, 128); + get_reg_bn(XMM7, 128); + get_reg_bn(XMM8, 128); + get_reg_bn(XMM9, 128); + get_reg_bn(XMM10, 128); + get_reg_bn(XMM11, 128); + get_reg_bn(XMM12, 128); + get_reg_bn(XMM13, 128); + get_reg_bn(XMM14, 128); + get_reg_bn(XMM15, 128); + + get_reg(tsc); + + return dict; +} + + +PyObject* cpu_set_gpreg(JitCpu* self, PyObject *args) +{ + PyObject* dict; + PyObject *d_key, *d_value = NULL; + const char *d_key_name; + Py_ssize_t pos = 0; + uint8_t val08; + uint16_t val16; + uint32_t val32; + uint64_t val64; + unsigned int i, found; + + if (!PyArg_ParseTuple(args, "O", &dict)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + if(!PyDict_Check(dict)) + RAISE(PyExc_TypeError, "arg must be dict"); + while(PyDict_Next(dict, &pos, &d_key, &d_value)){ + PyGetStr(d_key_name, d_key); + found = 0; + for (i=0; i < sizeof(gpreg_dict)/sizeof(reg_dict); i++){ + if (strcmp(d_key_name, gpreg_dict[i].name)) + continue; + found = 1; + switch (gpreg_dict[i].size) { + default: + RAISE(PyExc_TypeError, "Unsupported size"); + break; + case 8: + PyGetInt_uint8_t(d_value, val08); + *((uint8_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val08; + break; + case 16: + PyGetInt_uint16_t(d_value, val16); + *((uint16_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val16; + break; + case 32: + PyGetInt_uint32_t(d_value, val32); + *((uint32_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val32; + break; + case 64: + PyGetInt_uint64_t(d_value, val64); + *((uint64_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset)) = val64; + break; + case 128: + { + bn_t bn; + PyObject* py_long = d_value; + + +#if PY_MAJOR_VERSION >= 3 + if (PyLong_Check(py_long)){ + /* Already PyLong */ + /* Increment ref as we will decement it next */ + Py_INCREF(py_long); + } else { + RAISE(PyExc_TypeError,"arg must be int"); + } +#else + uint64_t tmp; + + if (PyInt_Check(py_long)){ + tmp = (uint64_t)PyInt_AsLong(py_long); + py_long = PyLong_FromLong((long)tmp); + } else if (PyLong_Check(py_long)){ + /* Already PyLong */ + /* Increment ref as we will decement it next */ + Py_INCREF(py_long); + } + else{ + RAISE(PyExc_TypeError,"arg must be int"); + } +#endif + + bn = PyLong_to_bn(py_long); + *(bn_t*)(((char*)(self->cpu)) + gpreg_dict[i].offset) = bignum_mask(bn, 128); + } + break; + } + break; + } + + if (found) + continue; + fprintf(stderr, "unknown key: %s\n", d_key_name); + RAISE(PyExc_ValueError, "unknown reg"); + } + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * cpu_init_regs(JitCpu* self) +{ + memset(self->cpu, 0, sizeof(struct vm_cpu)); + ((struct vm_cpu*)self->cpu)->tsc = 0x1122334455667788ULL; + ((struct vm_cpu*)self->cpu)->i_f = 1; + Py_INCREF(Py_None); + return Py_None; + +} + +void dump_gpregs_16(struct vm_cpu* vmcpu) +{ + printf("EAX %.8"PRIX32" EBX %.8"PRIX32" ECX %.8"PRIX32" EDX %.8"PRIX32" ", + (uint32_t)(vmcpu->RAX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RBX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RCX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RDX & 0xFFFFFFFF)); + printf("ESI %.8"PRIX32" EDI %.8"PRIX32" ESP %.8"PRIX32" EBP %.8"PRIX32" ", + (uint32_t)(vmcpu->RSI & 0xFFFFFFFF), + (uint32_t)(vmcpu->RDI & 0xFFFFFFFF), + (uint32_t)(vmcpu->RSP & 0xFFFFFFFF), + (uint32_t)(vmcpu->RBP & 0xFFFFFFFF)); + printf("EIP %.8"PRIX32" ", + (uint32_t)(vmcpu->RIP & 0xFFFFFFFF)); + printf("zf %.1d nf %.1d of %.1d cf %.1d\n", + (uint32_t)(vmcpu->zf & 0x1), + (uint32_t)(vmcpu->nf & 0x1), + (uint32_t)(vmcpu->of & 0x1), + (uint32_t)(vmcpu->cf & 0x1)); +} + +void dump_gpregs_32(struct vm_cpu* vmcpu) +{ + + printf("EAX %.8"PRIX32" EBX %.8"PRIX32" ECX %.8"PRIX32" EDX %.8"PRIX32" ", + (uint32_t)(vmcpu->RAX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RBX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RCX & 0xFFFFFFFF), + (uint32_t)(vmcpu->RDX & 0xFFFFFFFF)); + printf("ESI %.8"PRIX32" EDI %.8"PRIX32" ESP %.8"PRIX32" EBP %.8"PRIX32" ", + (uint32_t)(vmcpu->RSI & 0xFFFFFFFF), + (uint32_t)(vmcpu->RDI & 0xFFFFFFFF), + (uint32_t)(vmcpu->RSP & 0xFFFFFFFF), + (uint32_t)(vmcpu->RBP & 0xFFFFFFFF)); + printf("EIP %.8"PRIX32" ", + (uint32_t)(vmcpu->RIP & 0xFFFFFFFF)); + printf("zf %.1d nf %.1d of %.1d cf %.1d\n", + (uint32_t)(vmcpu->zf & 0x1), + (uint32_t)(vmcpu->nf & 0x1), + (uint32_t)(vmcpu->of & 0x1), + (uint32_t)(vmcpu->cf & 0x1)); + +} + +void dump_gpregs_64(struct vm_cpu* vmcpu) +{ + + printf("RAX %.16"PRIX64" RBX %.16"PRIX64" RCX %.16"PRIX64" RDX %.16"PRIX64" ", + vmcpu->RAX, vmcpu->RBX, vmcpu->RCX, vmcpu->RDX); + printf("RSI %.16"PRIX64" RDI %.16"PRIX64" RSP %.16"PRIX64" RBP %.16"PRIX64" ", + vmcpu->RSI, vmcpu->RDI, vmcpu->RSP, vmcpu->RBP); + printf("RIP %.16"PRIX64"\n", + vmcpu->RIP); + printf("R8 %.16"PRIX64" R9 %.16"PRIX64" R10 %.16"PRIX64" R11 %.16"PRIX64" ", + vmcpu->R8, vmcpu->R9, vmcpu->R10, vmcpu->R11); + printf("R12 %.16"PRIX64" R13 %.16"PRIX64" R14 %.16"PRIX64" R15 %.16"PRIX64" ", + vmcpu->R12, vmcpu->R13, vmcpu->R14, vmcpu->R15); + + + printf("zf %.1d nf %.1d of %.1d cf %.1d\n", + vmcpu->zf, vmcpu->nf, vmcpu->of, vmcpu->cf); + +} + +PyObject * cpu_dump_gpregs(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + + vmcpu = self->cpu; + dump_gpregs_64(vmcpu); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject * cpu_dump_gpregs_with_attrib(JitCpu* self, PyObject* args) +{ + struct vm_cpu* vmcpu; + PyObject *item1; + uint64_t attrib; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(item1, attrib); + + vmcpu = self->cpu; + if (attrib == 16 || attrib == 32) + dump_gpregs_32(vmcpu); + else if (attrib == 64) + dump_gpregs_64(vmcpu); + else { + RAISE(PyExc_TypeError,"Bad attrib"); + } + + Py_INCREF(Py_None); + return Py_None; +} + + + +PyObject* cpu_set_exception(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_exception(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->exception_flags)); +} + +PyObject* cpu_set_interrupt_num(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint32_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint32_t(item1, exception_flags); + + ((struct vm_cpu*)self->cpu)->interrupt_num = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_interrupt_num(JitCpu* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(((struct vm_cpu*)self->cpu)->interrupt_num)); +} + +PyObject* cpu_set_segm_base(JitCpu* self, PyObject* args) +{ + PyObject *item1, *item2; + uint64_t segm_num, segm_base; + + if (!PyArg_ParseTuple(args, "OO", &item1, &item2)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(item1, segm_num); + PyGetInt_uint64_t(item2, segm_base); + ((struct vm_cpu*)self->cpu)->segm_base[segm_num & 0xFFFF] = segm_base; + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cpu_get_segm_base(JitCpu* self, PyObject* args) +{ + PyObject *item1; + uint64_t segm_num; + PyObject* v; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + PyGetInt_uint64_t(item1, segm_num); + v = PyLong_FromLong((long)(((struct vm_cpu*)self->cpu)->segm_base[segm_num & 0xFFFF])); + return v; +} + +uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr) +{ + return addr + ((struct vm_cpu*)jitcpu->cpu)->segm_base[segm & 0xFFFF]; +} + +void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src) +{ + vm_MEM_WRITE_08(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src) +{ + vm_MEM_WRITE_16(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src) +{ + vm_MEM_WRITE_32(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + +void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src) +{ + vm_MEM_WRITE_64(&((VmMngr*)jitcpu->pyvm)->vm_mngr, addr, src); +} + + + +static PyMemberDef JitCpu_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef JitCpu_methods[] = { + {"init_regs", (PyCFunction)cpu_init_regs, METH_NOARGS, + "X"}, + {"dump_gpregs", (PyCFunction)cpu_dump_gpregs, METH_NOARGS, + "X"}, + {"dump_gpregs_with_attrib", (PyCFunction)cpu_dump_gpregs_with_attrib, METH_VARARGS, + "X"}, + {"get_gpreg", (PyCFunction)cpu_get_gpreg, METH_NOARGS, + "X"}, + {"set_gpreg", (PyCFunction)cpu_set_gpreg, METH_VARARGS, + "X"}, + {"get_segm_base", (PyCFunction)cpu_get_segm_base, METH_VARARGS, + "X"}, + {"set_segm_base", (PyCFunction)cpu_set_segm_base, METH_VARARGS, + "X"}, + {"get_exception", (PyCFunction)cpu_get_exception, METH_VARARGS, + "X"}, + {"set_exception", (PyCFunction)cpu_set_exception, METH_VARARGS, + "X"}, + {"get_interrupt_num", (PyCFunction)cpu_get_interrupt_num, METH_VARARGS, + "X"}, + {"set_interrupt_num", (PyCFunction)cpu_set_interrupt_num, METH_VARARGS, + "X"}, + {NULL} /* Sentinel */ +}; + +static int +JitCpu_init(JitCpu *self, PyObject *args, PyObject *kwds) +{ + self->cpu = malloc(sizeof(struct vm_cpu)); + if (self->cpu == NULL) { + fprintf(stderr, "cannot alloc struct vm_cpu\n"); + exit(EXIT_FAILURE); + } + return 0; +} + +#define getset_reg_E_u32(regname) \ + static PyObject *JitCpu_get_E ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong((uint32_t)(self->cpu->R ## regname & 0xFFFFFFFF )); \ + } \ + static int JitCpu_set_E ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint32_t val32; \ + uint64_t val64; \ + PyGetInt_uint32_t_retneg(value, val32); \ + val64 = val32; \ + val64 |= self->cpu->R ##regname & 0xFFFFFFFF00000000ULL; \ + self->cpu->R ## regname = val64; \ + return 0; \ + } + + + +#define getset_reg_R_u16(regname) \ + static PyObject *JitCpu_get_ ## regname (JitCpu *self, void *closure) \ + { \ + return PyLong_FromUnsignedLongLong((uint16_t)(self->cpu->R ## regname & 0xFFFF )); \ + } \ + static int JitCpu_set_ ## regname (JitCpu *self, PyObject *value, void *closure) \ + { \ + uint16_t val16; \ + uint64_t val64; \ + PyGetInt_uint16_t_retneg(value, val16); \ + val64 = val16; \ + val64 |= self->cpu->R ##regname & 0xFFFFFFFFFFFF0000ULL; \ + self->cpu->R ## regname = val64; \ + return 0; \ + } + + +getset_reg_u64(RAX); +getset_reg_u64(RBX); +getset_reg_u64(RCX); +getset_reg_u64(RDX); +getset_reg_u64(RSI); +getset_reg_u64(RDI); +getset_reg_u64(RSP); +getset_reg_u64(RBP); + +getset_reg_u64(R8); +getset_reg_u64(R9); +getset_reg_u64(R10); +getset_reg_u64(R11); +getset_reg_u64(R12); +getset_reg_u64(R13); +getset_reg_u64(R14); +getset_reg_u64(R15); + +getset_reg_u64(RIP); + +getset_reg_u8(zf); +getset_reg_u8(nf); +getset_reg_u8(pf); +getset_reg_u8(of); +getset_reg_u8(cf); +getset_reg_u8(af); +getset_reg_u8(df); + + +getset_reg_u16(ES); +getset_reg_u16(CS); +getset_reg_u16(SS); +getset_reg_u16(DS); +getset_reg_u16(FS); +getset_reg_u16(GS); + +getset_reg_E_u32(AX); +getset_reg_E_u32(BX); +getset_reg_E_u32(CX); +getset_reg_E_u32(DX); +getset_reg_E_u32(SI); +getset_reg_E_u32(DI); +getset_reg_E_u32(SP); +getset_reg_E_u32(BP); +getset_reg_E_u32(IP); + +getset_reg_R_u16(AX); +getset_reg_R_u16(BX); +getset_reg_R_u16(CX); +getset_reg_R_u16(DX); +getset_reg_R_u16(SI); +getset_reg_R_u16(DI); +getset_reg_R_u16(SP); +getset_reg_R_u16(BP); + +getset_reg_R_u16(IP); + +getset_reg_u64(MM0); +getset_reg_u64(MM1); +getset_reg_u64(MM2); +getset_reg_u64(MM3); +getset_reg_u64(MM4); +getset_reg_u64(MM5); +getset_reg_u64(MM6); +getset_reg_u64(MM7); + +getset_reg_bn(XMM0, 128); +getset_reg_bn(XMM1, 128); +getset_reg_bn(XMM2, 128); +getset_reg_bn(XMM3, 128); +getset_reg_bn(XMM4, 128); +getset_reg_bn(XMM5, 128); +getset_reg_bn(XMM6, 128); +getset_reg_bn(XMM7, 128); +getset_reg_bn(XMM8, 128); +getset_reg_bn(XMM9, 128); +getset_reg_bn(XMM10, 128); +getset_reg_bn(XMM11, 128); +getset_reg_bn(XMM12, 128); +getset_reg_bn(XMM13, 128); +getset_reg_bn(XMM14, 128); +getset_reg_bn(XMM15, 128); + +getset_reg_u64(tsc); + +getset_reg_u32(exception_flags); +getset_reg_u32(interrupt_num); + + +PyObject* get_gpreg_offset_all(void) +{ + PyObject *dict = PyDict_New(); + PyObject *o; + get_reg_off(exception_flags); + + get_reg_off(RAX); + get_reg_off(RBX); + get_reg_off(RCX); + get_reg_off(RDX); + get_reg_off(RSI); + get_reg_off(RDI); + get_reg_off(RSP); + get_reg_off(RBP); + get_reg_off(R8); + get_reg_off(R9); + get_reg_off(R10); + get_reg_off(R11); + get_reg_off(R12); + get_reg_off(R13); + get_reg_off(R14); + get_reg_off(R15); + get_reg_off(RIP); + get_reg_off(zf); + get_reg_off(nf); + get_reg_off(pf); + get_reg_off(of); + get_reg_off(cf); + get_reg_off(af); + get_reg_off(df); + get_reg_off(tf); + get_reg_off(i_f); + get_reg_off(iopl_f); + get_reg_off(nt); + get_reg_off(rf); + get_reg_off(vm); + get_reg_off(ac); + get_reg_off(vif); + get_reg_off(vip); + get_reg_off(i_d); + get_reg_off(my_tick); + get_reg_off(cond); + + get_reg_off(float_st0); + get_reg_off(float_st1); + get_reg_off(float_st2); + get_reg_off(float_st3); + get_reg_off(float_st4); + get_reg_off(float_st5); + get_reg_off(float_st6); + get_reg_off(float_st7); + + get_reg_off(ES); + get_reg_off(CS); + get_reg_off(SS); + get_reg_off(DS); + get_reg_off(FS); + get_reg_off(GS); + + get_reg_off(MM0); + get_reg_off(MM1); + get_reg_off(MM2); + get_reg_off(MM3); + get_reg_off(MM4); + get_reg_off(MM5); + get_reg_off(MM6); + get_reg_off(MM7); + + get_reg_off(XMM0); + get_reg_off(XMM1); + get_reg_off(XMM2); + get_reg_off(XMM3); + get_reg_off(XMM4); + get_reg_off(XMM5); + get_reg_off(XMM6); + get_reg_off(XMM7); + get_reg_off(XMM8); + get_reg_off(XMM9); + get_reg_off(XMM10); + get_reg_off(XMM11); + get_reg_off(XMM12); + get_reg_off(XMM13); + get_reg_off(XMM14); + get_reg_off(XMM15); + + get_reg_off(tsc); + + get_reg_off(interrupt_num); + get_reg_off(exception_flags); + + get_reg_off(float_stack_ptr); + get_reg_off(reg_float_cs); + get_reg_off(reg_float_eip); + get_reg_off(reg_float_control); + + return dict; +} + + +static PyGetSetDef JitCpu_getseters[] = { + {"vmmngr", + (getter)JitCpu_get_vmmngr, (setter)JitCpu_set_vmmngr, + "vmmngr", + NULL}, + + {"vmcpu", + (getter)JitCpu_get_vmcpu, (setter)JitCpu_set_vmcpu, + "vmcpu", + NULL}, + + {"jitter", + (getter)JitCpu_get_jitter, (setter)JitCpu_set_jitter, + "jitter", + NULL}, + + + {"RAX", (getter)JitCpu_get_RAX, (setter)JitCpu_set_RAX, "RAX", NULL}, + {"RBX", (getter)JitCpu_get_RBX, (setter)JitCpu_set_RBX, "RBX", NULL}, + {"RCX", (getter)JitCpu_get_RCX, (setter)JitCpu_set_RCX, "RCX", NULL}, + {"RDX", (getter)JitCpu_get_RDX, (setter)JitCpu_set_RDX, "RDX", NULL}, + {"RSI", (getter)JitCpu_get_RSI, (setter)JitCpu_set_RSI, "RSI", NULL}, + {"RDI", (getter)JitCpu_get_RDI, (setter)JitCpu_set_RDI, "RDI", NULL}, + {"RSP", (getter)JitCpu_get_RSP, (setter)JitCpu_set_RSP, "RSP", NULL}, + {"RBP", (getter)JitCpu_get_RBP, (setter)JitCpu_set_RBP, "RBP", NULL}, + {"R8", (getter)JitCpu_get_R8, (setter)JitCpu_set_R8, "R8", NULL}, + {"R9", (getter)JitCpu_get_R9, (setter)JitCpu_set_R9, "R9", NULL}, + {"R10", (getter)JitCpu_get_R10, (setter)JitCpu_set_R10, "R10", NULL}, + {"R11", (getter)JitCpu_get_R11, (setter)JitCpu_set_R11, "R11", NULL}, + {"R12", (getter)JitCpu_get_R12, (setter)JitCpu_set_R12, "R12", NULL}, + {"R13", (getter)JitCpu_get_R13, (setter)JitCpu_set_R13, "R13", NULL}, + {"R14", (getter)JitCpu_get_R14, (setter)JitCpu_set_R14, "R14", NULL}, + {"R15", (getter)JitCpu_get_R15, (setter)JitCpu_set_R15, "R15", NULL}, + {"RIP", (getter)JitCpu_get_RIP, (setter)JitCpu_set_RIP, "RIP", NULL}, + {"zf", (getter)JitCpu_get_zf, (setter)JitCpu_set_zf, "zf", NULL}, + {"nf", (getter)JitCpu_get_nf, (setter)JitCpu_set_nf, "nf", NULL}, + {"pf", (getter)JitCpu_get_pf, (setter)JitCpu_set_pf, "pf", NULL}, + {"of", (getter)JitCpu_get_of, (setter)JitCpu_set_of, "of", NULL}, + {"cf", (getter)JitCpu_get_cf, (setter)JitCpu_set_cf, "cf", NULL}, + {"af", (getter)JitCpu_get_af, (setter)JitCpu_set_af, "af", NULL}, + {"df", (getter)JitCpu_get_df, (setter)JitCpu_set_df, "df", NULL}, + {"ES", (getter)JitCpu_get_ES, (setter)JitCpu_set_ES, "ES", NULL}, + {"CS", (getter)JitCpu_get_CS, (setter)JitCpu_set_CS, "CS", NULL}, + {"SS", (getter)JitCpu_get_SS, (setter)JitCpu_set_SS, "SS", NULL}, + {"DS", (getter)JitCpu_get_DS, (setter)JitCpu_set_DS, "DS", NULL}, + {"FS", (getter)JitCpu_get_FS, (setter)JitCpu_set_FS, "FS", NULL}, + {"GS", (getter)JitCpu_get_GS, (setter)JitCpu_set_GS, "GS", NULL}, + + {"EAX", (getter)JitCpu_get_EAX, (setter)JitCpu_set_EAX, "EAX", NULL}, + {"EBX", (getter)JitCpu_get_EBX, (setter)JitCpu_set_EBX, "EBX", NULL}, + {"ECX", (getter)JitCpu_get_ECX, (setter)JitCpu_set_ECX, "ECX", NULL}, + {"EDX", (getter)JitCpu_get_EDX, (setter)JitCpu_set_EDX, "EDX", NULL}, + {"ESI", (getter)JitCpu_get_ESI, (setter)JitCpu_set_ESI, "ESI", NULL}, + {"EDI", (getter)JitCpu_get_EDI, (setter)JitCpu_set_EDI, "EDI", NULL}, + {"ESP", (getter)JitCpu_get_ESP, (setter)JitCpu_set_ESP, "ESP", NULL}, + {"EBP", (getter)JitCpu_get_EBP, (setter)JitCpu_set_EBP, "EBP", NULL}, + {"EIP", (getter)JitCpu_get_EIP, (setter)JitCpu_set_EIP, "EIP", NULL}, + + {"AX", (getter)JitCpu_get_AX, (setter)JitCpu_set_AX, "AX", NULL}, + {"BX", (getter)JitCpu_get_BX, (setter)JitCpu_set_BX, "BX", NULL}, + {"CX", (getter)JitCpu_get_CX, (setter)JitCpu_set_CX, "CX", NULL}, + {"DX", (getter)JitCpu_get_DX, (setter)JitCpu_set_DX, "DX", NULL}, + {"SI", (getter)JitCpu_get_SI, (setter)JitCpu_set_SI, "SI", NULL}, + {"DI", (getter)JitCpu_get_DI, (setter)JitCpu_set_DI, "DI", NULL}, + {"SP", (getter)JitCpu_get_SP, (setter)JitCpu_set_SP, "SP", NULL}, + {"BP", (getter)JitCpu_get_BP, (setter)JitCpu_set_BP, "BP", NULL}, + + {"IP", (getter)JitCpu_get_IP, (setter)JitCpu_set_IP, "IP", NULL}, + + {"MM0", (getter)JitCpu_get_MM0, (setter)JitCpu_set_MM0, "MM0", NULL}, + {"MM1", (getter)JitCpu_get_MM1, (setter)JitCpu_set_MM1, "MM1", NULL}, + {"MM2", (getter)JitCpu_get_MM2, (setter)JitCpu_set_MM2, "MM2", NULL}, + {"MM3", (getter)JitCpu_get_MM3, (setter)JitCpu_set_MM3, "MM3", NULL}, + {"MM4", (getter)JitCpu_get_MM4, (setter)JitCpu_set_MM4, "MM4", NULL}, + {"MM5", (getter)JitCpu_get_MM5, (setter)JitCpu_set_MM5, "MM5", NULL}, + {"MM6", (getter)JitCpu_get_MM6, (setter)JitCpu_set_MM6, "MM6", NULL}, + {"MM7", (getter)JitCpu_get_MM7, (setter)JitCpu_set_MM7, "MM7", NULL}, + + {"XMM0", (getter)JitCpu_get_XMM0, (setter)JitCpu_set_XMM0, "XMM0", NULL}, + {"XMM1", (getter)JitCpu_get_XMM1, (setter)JitCpu_set_XMM1, "XMM1", NULL}, + {"XMM2", (getter)JitCpu_get_XMM2, (setter)JitCpu_set_XMM2, "XMM2", NULL}, + {"XMM3", (getter)JitCpu_get_XMM3, (setter)JitCpu_set_XMM3, "XMM3", NULL}, + {"XMM4", (getter)JitCpu_get_XMM4, (setter)JitCpu_set_XMM4, "XMM4", NULL}, + {"XMM5", (getter)JitCpu_get_XMM5, (setter)JitCpu_set_XMM5, "XMM5", NULL}, + {"XMM6", (getter)JitCpu_get_XMM6, (setter)JitCpu_set_XMM6, "XMM6", NULL}, + {"XMM7", (getter)JitCpu_get_XMM7, (setter)JitCpu_set_XMM7, "XMM7", NULL}, + {"XMM8", (getter)JitCpu_get_XMM8, (setter)JitCpu_set_XMM8, "XMM8", NULL}, + {"XMM9", (getter)JitCpu_get_XMM9, (setter)JitCpu_set_XMM9, "XMM9", NULL}, + {"XMM10", (getter)JitCpu_get_XMM10, (setter)JitCpu_set_XMM10, "XMM10", NULL}, + {"XMM11", (getter)JitCpu_get_XMM11, (setter)JitCpu_set_XMM11, "XMM11", NULL}, + {"XMM12", (getter)JitCpu_get_XMM12, (setter)JitCpu_set_XMM12, "XMM12", NULL}, + {"XMM13", (getter)JitCpu_get_XMM13, (setter)JitCpu_set_XMM13, "XMM13", NULL}, + {"XMM14", (getter)JitCpu_get_XMM14, (setter)JitCpu_set_XMM14, "XMM14", NULL}, + {"XMM15", (getter)JitCpu_get_XMM15, (setter)JitCpu_set_XMM15, "XMM15", NULL}, + + {"tsc", (getter)JitCpu_get_tsc, (setter)JitCpu_set_tsc, "tsc", NULL}, + + {"exception_flags", (getter)JitCpu_get_exception_flags, (setter)JitCpu_set_exception_flags, "exception_flags", NULL}, + {"interrupt_num", (getter)JitCpu_get_interrupt_num, (setter)JitCpu_set_interrupt_num, "interrupt_num", NULL}, + + + {NULL} /* Sentinel */ +}; + + +static PyTypeObject JitCpuType = { + PyVarObject_HEAD_INIT(NULL, 0) + "JitCore_x86.JitCpu", /*tp_name*/ + sizeof(JitCpu), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)JitCpu_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "JitCpu objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + JitCpu_methods, /* tp_methods */ + JitCpu_members, /* tp_members */ + JitCpu_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)JitCpu_init, /* tp_init */ + 0, /* tp_alloc */ + JitCpu_new, /* tp_new */ +}; + + + +static PyMethodDef JitCore_x86_Methods[] = { + + /* + + */ + {"get_gpreg_offset_all", (PyCFunction)get_gpreg_offset_all, METH_NOARGS}, + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + + +MOD_INIT(JitCore_x86) +{ + PyObject *module = NULL; + + MOD_DEF(module, "JitCore_x86", "JitCore_x86 module", JitCore_x86_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&JitCpuType) < 0) + RET_MODULE; + + Py_INCREF(&JitCpuType); + if (PyModule_AddObject(module, "JitCpu", (PyObject *)&JitCpuType) < 0) + RET_MODULE; + + RET_MODULE; +} diff --git a/src/miasm/jitter/arch/JitCore_x86.h b/src/miasm/jitter/arch/JitCore_x86.h new file mode 100644 index 00000000..5c005e86 --- /dev/null +++ b/src/miasm/jitter/arch/JitCore_x86.h @@ -0,0 +1,136 @@ +#include "../bn.h" + +#if _WIN32 +#define _MIASM_EXPORT __declspec(dllexport) +#else +#define _MIASM_EXPORT +#endif + +struct vm_cpu { + uint32_t exception_flags; + uint32_t interrupt_num; + + + /* gpregs */ + uint64_t RAX; + uint64_t RBX; + uint64_t RCX; + uint64_t RDX; + uint64_t RSI; + uint64_t RDI; + uint64_t RSP; + uint64_t RBP; + uint64_t R8; + uint64_t R9; + uint64_t R10; + uint64_t R11; + uint64_t R12; + uint64_t R13; + uint64_t R14; + uint64_t R15; + + uint64_t RIP; + + /* eflag */ + uint8_t zf; + uint8_t nf; + uint8_t pf; + uint8_t of; + uint8_t cf; + uint8_t af; + uint8_t df; + + uint8_t tf; + uint8_t i_f; + uint8_t iopl_f; + uint8_t nt; + uint8_t rf; + uint8_t vm; + uint8_t ac; + uint8_t vif; + uint8_t vip; + uint8_t i_d; + + bn_t my_tick; + + bn_t cond; + + uint64_t float_st0; + uint64_t float_st1; + uint64_t float_st2; + uint64_t float_st3; + uint64_t float_st4; + uint64_t float_st5; + uint64_t float_st6; + uint64_t float_st7; + + unsigned int float_c0; + unsigned int float_c1; + unsigned int float_c2; + unsigned int float_c3; + + + unsigned int float_stack_ptr; + + unsigned int reg_float_control; + + unsigned int reg_float_eip; + unsigned int reg_float_cs; + unsigned int reg_float_address; + unsigned int reg_float_ds; + + + uint64_t tsc; + + + uint16_t ES; + uint16_t CS; + uint16_t SS; + uint16_t DS; + uint16_t FS; + uint16_t GS; + + unsigned int cr0; + unsigned int cr3; + + uint64_t MM0; + uint64_t MM1; + uint64_t MM2; + uint64_t MM3; + uint64_t MM4; + uint64_t MM5; + uint64_t MM6; + uint64_t MM7; + + /* SSE */ + bn_t XMM0; + bn_t XMM1; + bn_t XMM2; + bn_t XMM3; + bn_t XMM4; + bn_t XMM5; + bn_t XMM6; + bn_t XMM7; + bn_t XMM8; + bn_t XMM9; + bn_t XMM10; + bn_t XMM11; + bn_t XMM12; + bn_t XMM13; + bn_t XMM14; + bn_t XMM15; + + uint64_t segm_base[0x10000]; + +}; + +_MIASM_EXPORT void dump_gpregs_32(struct vm_cpu* vmcpu); +_MIASM_EXPORT void dump_gpregs_64(struct vm_cpu* vmcpu); +_MIASM_EXPORT uint64_t segm2addr(JitCpu* jitcpu, uint64_t segm, uint64_t addr); + +_MIASM_EXPORT void MEM_WRITE_08(JitCpu* jitcpu, uint64_t addr, uint8_t src); +_MIASM_EXPORT void MEM_WRITE_16(JitCpu* jitcpu, uint64_t addr, uint16_t src); +_MIASM_EXPORT void MEM_WRITE_32(JitCpu* jitcpu, uint64_t addr, uint32_t src); +_MIASM_EXPORT void MEM_WRITE_64(JitCpu* jitcpu, uint64_t addr, uint64_t src); + +#define RETURN_PC return BlockDst; diff --git a/src/miasm/jitter/arch/__init__.py b/src/miasm/jitter/arch/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/miasm/jitter/arch/__init__.py diff --git a/src/miasm/jitter/bn.c b/src/miasm/jitter/bn.c new file mode 100644 index 00000000..43e552a4 --- /dev/null +++ b/src/miasm/jitter/bn.c @@ -0,0 +1,933 @@ +/* + +Big number library - arithmetic on multiple-precision unsigned integers. + +This library is an implementation of arithmetic on arbitrarily large integers. + +The difference between this and other implementations, is that the data structure +has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM), +and all memory is allocated statically: no dynamic allocation for better or worse. + +Primary goals are correctness, clarity of code and clean, portable implementation. +Secondary goal is a memory footprint small enough to make it suitable for use in +embedded applications. + + +The current state is correct functionality and adequate performance. +There may well be room for performance-optimizations and improvements. + +Source: https://github.com/kokke/tiny-bignum-c + +Code slightly modified to support ast generation calculus style from Expr. + +*/ + +#include <stdio.h> +#include <stdbool.h> +#include <inttypes.h> +#include <assert.h> +#include "bn.h" + +/* Functions for shifting number in-place. */ +static bn_t _lshift_one_bit(bn_t a); +static bn_t _rshift_one_bit(bn_t a); +static bn_t _lshift_word(bn_t a, int nwords); +static bn_t _rshift_word(bn_t a, int nwords); + + + + +/* Public / Exported functions. */ +bn_t bignum_init(void) +{ + int i; + bn_t n; + + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + n.array[i] = 0; + } + + return n; +} + + +bn_t bignum_from_int(DTYPE_TMP i) +{ + bn_t n; + + n = bignum_init(); + /* Endianness issue if machine is not little-endian? */ +#ifdef WORD_SIZE + #if (WORD_SIZE == 1) + n.array[0] = (i & 0x000000ff); + n.array[1] = (i & 0x0000ff00) >> 8; + n.array[2] = (i & 0x00ff0000) >> 16; + n.array[3] = (i & 0xff000000) >> 24; + #elif (WORD_SIZE == 2) + n.array[0] = (i & 0x0000ffff); + n.array[1] = (i & 0xffff0000) >> 16; + #elif (WORD_SIZE == 4) + n.array[0] = (DTYPE)i; + DTYPE_TMP num_32 = 32; + DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */ + n.array[1] = (DTYPE)tmp; + #endif +#endif + + return n; +} + + + +bn_t bignum_from_uint64(uint64_t i) +{ + bn_t n; + n = bignum_init(); + /* Endianness issue if machine is not little-endian? */ +#ifdef WORD_SIZE + #if (WORD_SIZE == 1) + n.array[0] = (i & 0x000000ff); + n.array[1] = (i & 0x0000ff00) >> 8; + n.array[2] = (i & 0x00ff0000) >> 16; + n.array[3] = (i & 0xff000000) >> 24; + #elif (WORD_SIZE == 2) + n.array[0] = (i & 0x0000ffff); + n.array[1] = (i & 0xffff0000) >> 16; + #elif (WORD_SIZE == 4) + n.array[0] = (DTYPE)i; + DTYPE_TMP num_32 = 32; + DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */ + n.array[1] = (DTYPE)tmp; + #endif +#endif + + return n; +} + + + + + +int bignum_to_int(bn_t n) +{ + + int ret = 0; + + /* Endianness issue if machine is not little-endian? */ +#if (WORD_SIZE == 1) + ret += n.array[0]; + ret += n.array[1] << 8; + ret += n.array[2] << 16; + ret += n.array[3] << 24; +#elif (WORD_SIZE == 2) + ret += n.array[0]; + ret += n.array[1] << 16; +#elif (WORD_SIZE == 4) + ret += n.array[0]; +#endif + + + return ret; +} + + +uint64_t bignum_to_uint64(bn_t n) +{ + + uint64_t ret = 0; + + /* Endianness issue if machine is not little-endian? */ +#if (WORD_SIZE == 1) + ret += (uint64_t)(n.array[0]); + ret += (uint64_t)(n.array[1]) << 8; + ret += (uint64_t)(n.array[2]) << 16; + ret += (uint64_t)(n.array[3]) << 24; + + ret += (uint64_t)(n.array[4]) << 32; + ret += (uint64_t)(n.array[5]) << 40; + ret += (uint64_t)(n.array[6]) << 48; + ret += (uint64_t)(n.array[7]) << 56; + + +#elif (WORD_SIZE == 2) + ret += (uint64_t)(n.array[0]); + ret += (uint64_t)(n.array[1]) << 16; + ret += (uint64_t)(n.array[2]) << 32; + ret += (uint64_t)(n.array[3]) << 48; +#elif (WORD_SIZE == 4) + ret += n.array[0]; + ret += (uint64_t)(n.array[1]) << 32; +#endif + + return ret; +} + + + + +bn_t bignum_from_string(char* str, int nbytes) +{ + + require(str, "str is null"); + require(nbytes > 0, "nbytes must be positive"); + require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes"); + + bn_t n; + + n = bignum_init(); + + DTYPE tmp; /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */ + int i = nbytes - (2 * WORD_SIZE); /* index into string */ + int j = 0; /* index into array */ + + /* reading last hex-byte "MSB" from string first -> big endian */ + /* MSB ~= most significant byte / block ? :) */ + while (i >= 0) { + tmp = 0; + sscanf(&str[i], SSCANF_FORMAT_STR, &tmp); + n.array[j] = tmp; + i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */ + j += 1; /* step one element forward in the array. */ + } + + return n; +} + +void bignum_to_string(bn_t n, char* str, int nbytes) +{ + require(str, "str is null"); + require(nbytes > 0, "nbytes must be positive"); + require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes"); + + int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */ + int i = 0; /* index into string representation. */ + + /* reading last array-element "MSB" first -> big endian */ + while ((j >= 0) && (nbytes > (i + 1))) { + sprintf(&str[i], SPRINTF_FORMAT_STR, n.array[j]); + i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */ + j -= 1; /* step one element back in the array. */ + } + + /* Zero-terminate string */ + str[i] = 0; +} + + + +bn_t bignum_dec(bn_t n) +{ + //require(n, "n is null"); + + DTYPE tmp; /* copy of n */ + DTYPE res; + + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + tmp = n.array[i]; + res = tmp - 1; + n.array[i] = res; + + if (!(res > tmp)) { + break; + } + } + + return n; +} + + +bn_t bignum_inc(bn_t n) +{ + //require(n, "n is null"); + + DTYPE res; + DTYPE tmp; /* copy of n */ + + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + tmp = n.array[i]; + res = tmp + 1; + n.array[i] = res; + + if (res > tmp) { + break; + } + } + + return n; +} + + + +bn_t bignum_add(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + bn_t c; + + DTYPE_TMP tmp; + int carry = 0; + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + tmp = (DTYPE_TMP)a.array[i] + b.array[i] + carry; + carry = (tmp > MAX_VAL); + c.array[i] = (tmp & MAX_VAL); + } + + return c; +} + + +bn_t bignum_sub(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + bn_t c; + + DTYPE_TMP res; + DTYPE_TMP tmp1; + DTYPE_TMP tmp2; + int borrow = 0; + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + tmp1 = (DTYPE_TMP)a.array[i] + (MAX_VAL + 1); /* + number_base */ + tmp2 = (DTYPE_TMP)b.array[i] + borrow;; + res = (tmp1 - tmp2); + c.array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */ + borrow = (res <= MAX_VAL); + } + + return c; +} + + + + +bn_t bignum_mul(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + + bn_t c; + bn_t row; + bn_t tmp; + int i, j; + + c = bignum_init(); + + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + row = bignum_init(); + + for (j = 0; j < BN_ARRAY_SIZE; ++j) { + if (i + j < BN_ARRAY_SIZE) { + tmp = bignum_init(); + DTYPE_TMP intermediate = ((DTYPE_TMP)a.array[i] * (DTYPE_TMP)b.array[j]); + tmp = bignum_from_int(intermediate); + tmp = _lshift_word(tmp, i + j); + row = bignum_add(tmp, row); + } + } + c = bignum_add(c, row); + } + + return c; +} + + +bn_t bignum_udiv(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + + bn_t c; + bn_t current; + bn_t denom; + bn_t tmp; + + current = bignum_from_int(1); // int current = 1; + denom = bignum_assign(b); // denom = b + tmp = bignum_assign(a); // tmp = a + + const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2); + bool overflow = false; + + while (bignum_cmp(denom, a) != LARGER) { // while (denom <= a) { + if (denom.array[BN_ARRAY_SIZE - 1] >= half_max) { + overflow = true; + break; + } + current = _lshift_one_bit(current); // current <<= 1; + denom = _lshift_one_bit(denom); // denom <<= 1; + } + if (!overflow) { + denom = _rshift_one_bit(denom); // denom >>= 1; + current = _rshift_one_bit(current); // current >>= 1; + } + c = bignum_init(); // int answer = 0; + + while (!bignum_is_zero(current)) { // while (current != 0) + if (bignum_cmp(tmp, denom) != SMALLER) { // if (dividend >= denom) + tmp = bignum_sub(tmp, denom); // dividend -= denom; + c = bignum_or(c, current); // answer |= current; + } + current = _rshift_one_bit(current); // current >>= 1; + denom = _rshift_one_bit(denom); // denom >>= 1; + } // return answer; + + return c; +} + + + +bn_t bignum_lshift(bn_t a, int nbits) +{ + //require(a, "a is null"); + //require(b, "b is null"); + require(nbits >= 0, "no negative shifts"); + + bn_t b; + + b = bignum_assign(a); + /* Handle shift in multiples of word-size */ + const int nbits_pr_word = (WORD_SIZE * 8); + int nwords = nbits / nbits_pr_word; + if (nwords != 0) { + b = _lshift_word(b, nwords); + nbits -= (nwords * nbits_pr_word); + } + + if (nbits != 0) { + int i; + for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) { + b.array[i] = (b.array[i] << nbits) | (b.array[i - 1] >> ((8 * WORD_SIZE) - nbits)); + } + b.array[i] <<= nbits; + } + + return b; +} + + +bn_t bignum_rshift(bn_t a, int nbits) +{ + //require(a, "a is null"); + //require(b, "b is null"); + require(nbits >= 0, "no negative shifts"); + + bn_t b; + + b = bignum_assign(a); + /* Handle shift in multiples of word-size */ + const int nbits_pr_word = (WORD_SIZE * 8); + int nwords = nbits / nbits_pr_word; + + if (nwords != 0) { + b = _rshift_word(b, nwords); + nbits -= (nwords * nbits_pr_word); + } + if (nbits != 0) { + int i; + for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) { + b.array[i] = (b.array[i] >> nbits) | (b.array[i + 1] << ((8 * WORD_SIZE) - nbits)); + } + b.array[i] >>= nbits; + } + + return b; +} + + + +bn_t bignum_a_rshift(bn_t a, int size, int nbits) +{ + //require(a, "a is null"); + //require(b, "b is null"); + require(nbits >= 0, "no negative shifts"); + require(size > 0, "no negative shifts"); + + bn_t b; + bn_t tmp, mask; + + b = bignum_rshift(a, nbits); + + /* get sign bit */ + tmp = bignum_rshift(a, size - 1); + tmp = bignum_mask(tmp, 1); + + if (!bignum_is_zero(tmp)) { + /* generate sign propag */ + tmp = bignum_from_int(1); + tmp = bignum_lshift(tmp, size); + tmp = bignum_dec(tmp); + + mask = bignum_from_int(1); + mask = bignum_lshift(mask, size - nbits); + mask = bignum_dec(mask); + + tmp = bignum_xor(tmp, mask); + b = bignum_or(b, tmp); + } + + return b; +} + +bn_t bignum_not(bn_t a) +{ + int i; + bn_t b; + + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + b.array[i] = ~a.array[i]; + } + + return b; +} + + + +bn_t bignum_umod(bn_t a, bn_t b) +{ + /* + Take divmod and throw away div part + */ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + + bn_t c, d; + bn_t tmp; + + /* c = (a / b) */ + c = bignum_udiv(a, b); + /* tmp = (c * b) */ + tmp = bignum_mul(c, b); + /* c = a - tmp */ + d = bignum_sub(a, tmp); + return d; +} + + +bn_t bignum_and(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + bn_t c; + + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + c.array[i] = (a.array[i] & b.array[i]); + } + + return c; +} + + +bn_t bignum_or(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + bn_t c; + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + c.array[i] = (a.array[i] | b.array[i]); + } + + return c; +} + + +bn_t bignum_xor(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + //require(c, "c is null"); + + bn_t c; + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + c.array[i] = (a.array[i] ^ b.array[i]); + } + return c; +} + + +int bignum_cmp(bn_t a, bn_t b) +{ + //require(a, "a is null"); + //require(b, "b is null"); + + int i = BN_ARRAY_SIZE; + do { + i -= 1; /* Decrement first, to start with last array element */ + if (a.array[i] > b.array[i]) { + return LARGER; + } + else if (a.array[i] < b.array[i]) { + return SMALLER; + } + } + while (i != 0); + + return EQUAL; +} + + +/* Signed compare bn */ +int bignum_cmp_signed(bn_t a, bn_t b) +{ + int i = BN_ARRAY_SIZE; + do { + i -= 1; /* Decrement first, to start with last array element */ + if ((DTYPE_SIGNED)a.array[i] > (DTYPE_SIGNED)b.array[i]) { + return LARGER; + } + else if ((DTYPE_SIGNED)a.array[i] < (DTYPE_SIGNED)b.array[i]) { + return SMALLER; + } + } + while (i != 0); + + return EQUAL; +} + + +/* Unsigned compare bn */ +int bignum_cmp_unsigned(bn_t a, bn_t b) +{ + return bignum_cmp(a, b); +} + + +/* Return 1 if a == b else 0 */ +int bignum_is_equal(bn_t a, bn_t b) +{ + int ret; + ret = bignum_cmp_unsigned(a, b); + if (ret == EQUAL) + return 1; + else + return 0; +} + + +/* Return 1 if a <u b else 0 */ +int bignum_is_inf_unsigned(bn_t a, bn_t b) +{ + int ret; + ret = bignum_cmp_unsigned(a, b); + if (ret == SMALLER) + return 1; + else + return 0; +} + + +/* Return 1 if a <=u b else 0 */ +int bignum_is_inf_equal_unsigned(bn_t a, bn_t b) +{ + int ret; + ret = bignum_cmp_unsigned(a, b); + if (ret == EQUAL || ret == SMALLER) + return 1; + else + return 0; +} + + +/* Return 1 if a <s b else 0 */ +int bignum_is_inf_signed(bn_t a, bn_t b) +{ + int ret; + ret = bignum_cmp_signed(a, b); + if (ret == SMALLER) + return 1; + else + return 0; +} + + +/* Return 1 if a <=s b else 0 */ +int bignum_is_inf_equal_signed(bn_t a, bn_t b) +{ + int ret; + ret = bignum_cmp_signed(a, b); + if (ret == EQUAL || ret == SMALLER) + return 1; + else + return 0; +} + + +int bignum_is_zero(bn_t n) +{ + //require(n, "n is null"); + + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + if (n.array[i]) { + return 0; + } + } + + return 1; +} + + + +bn_t bignum_assign(bn_t src) +{ + //require(dst, "dst is null"); + //require(src, "src is null"); + bn_t dst; + + int i; + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + dst.array[i] = src.array[i]; + } + + return dst; +} + + +bn_t bignum_mask(bn_t src, int bits) +{ + bn_t dst; + bn_t mask; + + mask = bignum_from_int(0); + mask = bignum_dec(mask); + mask = bignum_rshift(mask, BN_BIT_SIZE - bits); + dst = bignum_and(src, mask); + return dst; +} + +/* Private / Static functions. */ +static bn_t _rshift_word(bn_t a, int nwords) +{ + /* Naive method: */ + //require(a, "a is null"); + int i; + + require(nwords >= 0, "no negative shifts"); + + if (nwords >= BN_ARRAY_SIZE) { + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + a.array[i] = 0; + } + return a; + } + + for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i) { + a.array[i] = a.array[i + nwords]; + } + + for (; i < BN_ARRAY_SIZE; ++i) { + a.array[i] = 0; + } + + return a; +} + + +static bn_t _lshift_word(bn_t a, int nwords) +{ + //require(a, "a is null"); + require(nwords >= 0, "no negative shifts"); + + int i; + + if (nwords >= BN_ARRAY_SIZE) { + for (i = 0; i < BN_ARRAY_SIZE; ++i) { + a.array[i] = 0; + } + return a; + } + + /* Shift whole words */ + for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i) { + a.array[i] = a.array[i - nwords]; + } + /* Zero pad shifted words. */ + for (; i >= 0; --i) { + a.array[i] = 0; + } + + return a; +} + + +static bn_t _lshift_one_bit(bn_t a) +{ + //require(a, "a is null"); + + int i; + for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) { + a.array[i] = (a.array[i] << 1) | (a.array[i - 1] >> ((8 * WORD_SIZE) - 1)); + } + a.array[0] <<= 1; + + return a; +} + + +static bn_t _rshift_one_bit(bn_t a) +{ + //require(a, "a is null"); + + int i; + for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) { + a.array[i] = (a.array[i] >> 1) | (a.array[i + 1] << ((8 * WORD_SIZE) - 1)); + } + a.array[BN_ARRAY_SIZE - 1] >>= 1; + + return a; +} + + +bn_t bignum_rol(bn_t a, int size, int nbits) +{ + bn_t c; + + c = bignum_or( + bignum_lshift(a, nbits), + bignum_rshift(a, size - nbits) + ); + c = bignum_mask(c, size); + return c; +} + + +bn_t bignum_ror(bn_t a, int size, int nbits) +{ + bn_t c; + + c = bignum_or( + bignum_rshift(a, nbits), + bignum_lshift(a, size - nbits) + ); + c = bignum_mask(c, size); + return c; +} + + +int bignum_getbit(bn_t a, int pos) +{ + int d_pos, bit_pos; + + require(pos < BN_BIT_SIZE, "size must be below bignum max size"); + + d_pos = pos / (sizeof(DTYPE) * 8); + bit_pos = pos % (sizeof(DTYPE) * 8); + return !!(a.array[d_pos] & (1 << bit_pos)); + +} + + + +/* + * Count leading zeros - count the number of zero starting at the most + * significant bit + * + * Example: + * - cntleadzeros(size=32, src=2): 30 + * - cntleadzeros(size=32, src=0): 32 + */ +int bignum_cntleadzeros(bn_t n, int size) +{ + int i; + + require(size, "size must be greater than 0"); + require(size <= BN_BIT_SIZE, "size must be below bignum max size"); + + for (i = 0; i < size; i++) { + if (bignum_getbit(n, size - i - 1)) + break; + } + + return i; +} + + + +/* + * Count trailing zeros - count the number of zero starting at the least + * significant bit + * + * Example: + * - cnttrailzeros(size=32, src=2): 1 + * - cnttrailzeros(size=32, src=0): 32 + */ +int bignum_cnttrailzeros(bn_t n, int size) +{ + int i; + + require(size, "size must be greater than 0"); + require(size <= BN_BIT_SIZE, "size must be below bignum max size"); + + for (i = 0; i < size; i++) { + if (bignum_getbit(n, i)) + break; + } + + return i; +} + + + + +bn_t bignum_sdiv(bn_t a, bn_t b, int size) +{ + require(size, "size must be greater than 0"); + require(size <= BN_BIT_SIZE, "size must be below bignum max size"); + + int a_sign, b_sign; + bn_t c; + + a_sign = bignum_getbit(a, size - 1); + b_sign = bignum_getbit(b, size - 1); + + if (a_sign) { + /* neg a */ + printf("a neg\n"); + a = bignum_sub(bignum_from_int(0), a); + a = bignum_mask(a, size - 1); + } + + if (b_sign) { + /* neg b */ + printf("b neg\n"); + b = bignum_sub(bignum_from_int(0), b); + b = bignum_mask(b, size - 1); + } + + c = bignum_udiv(a, b); + if (a_sign ^ b_sign) { + c = bignum_sub(bignum_from_int(0), c); + } + + c = bignum_mask(c, size); + return c; +} + + + +bn_t bignum_smod(bn_t a, bn_t b, int size) +{ + require(size, "size must be greater than 0"); + require(size <= BN_BIT_SIZE, "size must be below bignum max size"); + + bn_t c; + + c = bignum_sdiv(a, b, size); + c = bignum_mul(c, b); + c = bignum_sub(a, c); + c = bignum_mask(c, size); + return c; +} diff --git a/src/miasm/jitter/bn.h b/src/miasm/jitter/bn.h new file mode 100644 index 00000000..8c4a8ba1 --- /dev/null +++ b/src/miasm/jitter/bn.h @@ -0,0 +1,163 @@ +#ifndef __BIGNUM_H__ +#define __BIGNUM_H__ + +#if _WIN32 +#define _MIASM_EXPORT __declspec(dllexport) +#else +#define _MIASM_EXPORT +#endif + +/* + +Big number library - arithmetic on multiple-precision unsigned integers. + +This library is an implementation of arithmetic on arbitrarily large integers. + +The difference between this and other implementations, is that the data structure +has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM), +and all memory is allocated statically: no dynamic allocation for better or worse. + +Primary goals are correctness, clarity of code and clean, portable implementation. +Secondary goal is a memory footprint small enough to make it suitable for use in +embedded applications. + + +The current state is correct functionality and adequate performance. +There may well be room for performance-optimizations and improvements. + +Source: https://github.com/kokke/tiny-bignum-c + +Code slightly modified to support ast generation calculus style from Expr. + +*/ + +#include <stdint.h> +#include <assert.h> + + +/* This macro defines the word size in bytes of the array that constitutes the big-number data structure. */ +#ifndef WORD_SIZE + #define WORD_SIZE 4 +#endif + +#define BN_BYTE_SIZE 32 + +#define BN_BIT_SIZE ((BN_BYTE_SIZE) * 8) + +/* Size of big-numbers in bytes */ +//#define BN_ARRAY_SIZE (128 / WORD_SIZE) +#define BN_ARRAY_SIZE (BN_BYTE_SIZE / WORD_SIZE) + + +/* Here comes the compile-time specialization for how large the underlying array size should be. */ +/* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */ +#ifndef WORD_SIZE + #error Must define WORD_SIZE to be 1, 2, 4 +#elif (WORD_SIZE == 1) + /* Data type of array in structure */ + #define DTYPE uint8_t + #define DTYPE_SIGNED int8_t + /* bitmask for getting MSB */ + #define DTYPE_MSB ((DTYPE_TMP)(0x80)) + /* Data-type larger than DTYPE, for holding intermediate results of calculations */ + #define DTYPE_TMP uint32_t + /* sprintf format string */ + #define SPRINTF_FORMAT_STR "%.02x" + #define SSCANF_FORMAT_STR "%2hhx" + /* Max value of integer type */ + #define MAX_VAL ((DTYPE_TMP)0xFF) +#elif (WORD_SIZE == 2) + #define DTYPE uint16_t + #define DTYPE_SIGNED int16_t + #define DTYPE_TMP uint32_t + #define DTYPE_MSB ((DTYPE_TMP)(0x8000)) + #define SPRINTF_FORMAT_STR "%.04x" + #define SSCANF_FORMAT_STR "%4hx" + #define MAX_VAL ((DTYPE_TMP)0xFFFF) +#elif (WORD_SIZE == 4) + #define DTYPE uint32_t + #define DTYPE_SIGNED int32_t + #define DTYPE_TMP uint64_t + #define DTYPE_MSB ((DTYPE_TMP)(0x80000000)) + #define SPRINTF_FORMAT_STR "%.08x" + #define SSCANF_FORMAT_STR "%8x" + #define MAX_VAL ((DTYPE_TMP)0xFFFFFFFF) +#endif +#ifndef DTYPE + #error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever +#endif + + +/* Custom assert macro - easy to disable */ +#define require(p, msg) assert(p && #msg) + + +/* Data-holding structure: array of DTYPEs */ +typedef struct bn +{ + DTYPE array[BN_ARRAY_SIZE]; +} bn_t; + + + +/* Tokens returned by bignum_cmp() for value comparison */ +enum { SMALLER = -1, EQUAL = 0, LARGER = 1 }; + +/* Initialization functions: */ +_MIASM_EXPORT bn_t bignum_init(void); +_MIASM_EXPORT bn_t bignum_from_int(DTYPE_TMP i); +_MIASM_EXPORT bn_t bignum_from_uint64(uint64_t i); +_MIASM_EXPORT int bignum_to_int(bn_t n); +_MIASM_EXPORT uint64_t bignum_to_uint64(bn_t n); +_MIASM_EXPORT bn_t bignum_from_string(char* str, int nbytes); +_MIASM_EXPORT void bignum_to_string(bn_t n, char* str, int maxsize); + + +/* Basic arithmetic operations: */ +_MIASM_EXPORT bn_t bignum_add(bn_t a, bn_t b); /* c = a + b */ +_MIASM_EXPORT bn_t bignum_sub(bn_t a, bn_t b); /* c = a - b */ +_MIASM_EXPORT bn_t bignum_mul(bn_t a, bn_t b); /* c = a * b */ +_MIASM_EXPORT bn_t bignum_udiv(bn_t a, bn_t b); /* c = a / b */ +_MIASM_EXPORT bn_t bignum_umod(bn_t a, bn_t b); /* c = a % b */ +_MIASM_EXPORT bn_t bignum_sdiv(bn_t a, bn_t b, int size); +_MIASM_EXPORT bn_t bignum_smod(bn_t a, bn_t b, int size); +//void bignum_udivmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */ + + + +/* Bitwise operations: */ +_MIASM_EXPORT bn_t bignum_and(bn_t a, bn_t b); /* c = a & b */ +_MIASM_EXPORT bn_t bignum_or(bn_t a, bn_t b); /* c = a | b */ +_MIASM_EXPORT bn_t bignum_xor(bn_t a, bn_t b); /* c = a ^ b */ +_MIASM_EXPORT bn_t bignum_lshift(bn_t a, int nbits); /* b = a << nbits */ +_MIASM_EXPORT bn_t bignum_rshift(bn_t a, int nbits); /* b = a >> nbits */ +_MIASM_EXPORT bn_t bignum_a_rshift(bn_t a, int size, int nbits); /* b = a a>> nbits */ +_MIASM_EXPORT bn_t bignum_not(bn_t a); /* c = ~a */ + +/* Special operators and comparison */ +_MIASM_EXPORT int bignum_cmp(bn_t a, bn_t b); /* Compare: returns LARGER, EQUAL or SMALLER */ +_MIASM_EXPORT int bignum_is_equal(bn_t a, bn_t b); /* Return 1 if a == b else 0 */ +_MIASM_EXPORT int bignum_is_inf_unsigned(bn_t a, bn_t b); /* Return 1 if a <u b else 0 */ +_MIASM_EXPORT int bignum_is_inf_equal_unsigned(bn_t a, bn_t b); /* Return 1 if a <=u b else 0 */ +_MIASM_EXPORT int bignum_is_inf_signed(bn_t a, bn_t b); /* Return 1 if a <s b else 0 */ +_MIASM_EXPORT int bignum_is_inf_equal_signed(bn_t a, bn_t b); /* Return 1 if a <=s b else 0 */ + + + +_MIASM_EXPORT int bignum_is_zero(bn_t n); /* For comparison with zero */ +_MIASM_EXPORT bn_t bignum_inc(bn_t n); /* Increment: add one to n */ +_MIASM_EXPORT bn_t bignum_dec(bn_t n); /* Decrement: subtract one from n */ +//bn_t bignum_pow(bn_t a, bn_t b, bn_t c); /* Calculate a^b -- e.g. 2^10 => 1024 */ +//bn_t bignum_isqrt(bn_t a, bn_t b); /* Integer square root -- e.g. isqrt(5) => 2*/ +_MIASM_EXPORT int bignum_cntleadzeros(bn_t n, int size); +_MIASM_EXPORT int bignum_cnttrailzeros(bn_t n, int size); +_MIASM_EXPORT bn_t bignum_assign(bn_t src); /* Copy src into dst -- dst := src */ +_MIASM_EXPORT bn_t bignum_mask(bn_t src, int bits); /* c = src & ((1<<bits) -1) */ + +_MIASM_EXPORT bn_t bignum_rol(bn_t a, int size, int nbits); +_MIASM_EXPORT bn_t bignum_ror(bn_t a, int size, int nbits); +_MIASM_EXPORT int bignum_getbit(bn_t a, int pos); + +#endif /* #ifndef __BIGNUM_H__ */ + + diff --git a/src/miasm/jitter/codegen.py b/src/miasm/jitter/codegen.py new file mode 100644 index 00000000..305d6c36 --- /dev/null +++ b/src/miasm/jitter/codegen.py @@ -0,0 +1,656 @@ +""" +Module to generate C code for a given native @block +""" + +from builtins import zip +import warnings + +from future.utils import viewitems, viewvalues + +from miasm.expression.expression import ExprId, ExprLoc, ExprInt, \ + ExprMem, ExprCond, LocKey, is_expr +from miasm.ir.ir import IRBlock, AssignBlock + +from miasm.ir.translators.C import TranslatorC +from miasm.core.asmblock import AsmBlockBad +from miasm.expression.simplifications import expr_simp_high_to_explicit + +TRANSLATOR_NO_SYMBOL = TranslatorC(loc_db=None) + +SIZE_TO_MASK = {size: TRANSLATOR_NO_SYMBOL.from_expr(ExprInt(0, size).mask) + for size in (1, 2, 3, 7, 8, 16, 32, 64)} + + + + + + +class Attributes(object): + + """ + Store an irblock attributes + """ + + def __init__(self, log_mn=False, log_regs=False): + self.mem_read = False + self.mem_write = False + self.set_exception = False + self.log_mn = log_mn + self.log_regs = log_regs + self.instr = None + + +class CGen(object): + """ + Helper to generate C code for a given AsmBlock + """ + + """ + Translate native assembly block to C + """ + + CODE_EXCEPTION_MEM_AT_INSTR = r""" + // except fetch mem at instr noauto + if ((VM_exception_flag & ~EXCEPT_CODE_AUTOMOD) & EXCEPT_DO_NOT_UPDATE_PC) { + %s = %s; + BlockDst->address = %s; + return JIT_RET_EXCEPTION; + } + """ + + CODE_EXCEPTION_AT_INSTR = r""" + if (CPU_exception_flag_at_instr) { + %s = %s; + BlockDst->address = %s; + return JIT_RET_EXCEPTION; + } + """ + + CODE_RETURN_EXCEPTION = r""" + return JIT_RET_EXCEPTION; + """ + + CODE_RETURN_NO_EXCEPTION = r""" + %s: + %s = %s; + BlockDst->address = %s; + return JIT_RET_NO_EXCEPTION; + """ + + CODE_CPU_EXCEPTION_POST_INSTR = r""" + if (CPU_exception_flag) { + %s = DST_value; + BlockDst->address = DST_value; + return JIT_RET_EXCEPTION; + } + """ + + CODE_VM_EXCEPTION_POST_INSTR = r""" + check_memory_breakpoint(&(jitcpu->pyvm->vm_mngr)); + check_invalid_code_blocs(&(jitcpu->pyvm->vm_mngr)); + if (VM_exception_flag) { + %s = DST_value; + BlockDst->address = DST_value; + return JIT_RET_EXCEPTION; + } + """ + + CODE_INIT = r""" + int DST_case; + uint64_t DST_value; + struct vm_cpu *mycpu = jitcpu->cpu; + + goto %s; + """ + + CODE_BAD_BLOCK = r""" + // Unknown mnemonic + CPU_exception_flag = EXCEPT_UNK_MNEMO; + """ + CODE_RETURN_EXCEPTION + + def __init__(self, lifter): + self.lifter = lifter + self.PC = self.lifter.pc + self.translator = TranslatorC(self.lifter.loc_db) + self.init_arch_C() + + @property + def ir_arch(self): + warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"') + return self.lifter + + def init_arch_C(self): + """Iinitialize jitter internals""" + self.id_to_c_id = {} + for reg in self.lifter.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 dst_to_c(self, src): + """Translate Expr @src into C code""" + if not is_expr(src): + src = ExprInt(src, self.PC.size) + return self.id_to_c(src) + + def patch_c_id(self, expr): + """Replace ExprId in @expr with corresponding C variables""" + return expr.replace_expr(self.id_to_c_id) + + def id_to_c(self, expr): + """Translate Expr @expr into corresponding C code""" + return self.translator.from_expr(self.patch_c_id(expr)) + + def add_label_index(self, dst2index, loc_key): + """Insert @lbl to the dictionary @dst2index with a uniq value + @dst2index: LocKey -> uniq value + @loc_key: LocKey instance""" + + if loc_key not in dst2index: + dst2index[loc_key] = len(dst2index) + + 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.lifter.IRDst not in assignblk: + offset = instr.offset + instr.l + loc_key = self.lifter.loc_db.get_or_create_offset_location(offset) + dst = ExprLoc(loc_key, self.lifter.IRDst.size) + new_assignblk[self.lifter.IRDst] = dst + irs = [AssignBlock(new_assignblk, instr)] + return IRBlock(self.lifter.loc_db, self.lifter.get_loc_key_for_instr(instr), irs) + + 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.lifter.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 = self.lifter.irbloc_fix_regs_for_mode(irblock, self.lifter.attrib) + new_irblock = new_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 add_local_var(self, dst_var, dst_index, expr): + """ + Add local variable used to store temporary result + @dst_var: dictionary of Expr -> local_var_expr + @dst_index : dictionary 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 get_mem_prefetch(self, assignblk): + """ + Generate temporary variables used to fetch memory used in the @assignblk + Return a dictionary: 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 gen_c_assignments(self, assignblk): + """ + Return C information 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 viewitems(prefetchers): + 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 viewvalues(prefetchers): + 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 viewitems(assignblk): + src = src.replace_expr(prefetchers) + if dst == self.lifter.IRDst: + pass + elif isinstance(dst, ExprId): + new_dst = self.add_local_var(dst_var, dst_index, dst) + if dst in self.lifter.arch.regs.regs_flt_expr: + # Don't mask float assignment + 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.ptr.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 viewitems(dst_var): + if dst == self.lifter.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_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_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 traverse_expr_dst(self, expr, dst2index): + """ + Generate the index of the destination label for the @expr + @dst2index: dictionary 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.lifter.loc_db.get_or_create_offset_location(offset) + self.add_label_index(dst2index, loc_key) + out = hex(offset) + return ("%s" % dst2index[loc_key], out) + if expr.is_loc(): + loc_key = expr.loc_key + offset = self.lifter.loc_db.get_location_offset(expr.loc_key) + if offset is not None: + self.add_label_index(dst2index, loc_key) + out = hex(offset) + return ("%s" % dst2index[loc_key], out) + self.add_label_index(dst2index, loc_key) + out = hex(0) + return ("%s" % dst2index[loc_key], out) + dst2index[expr] = -1 + return ("-1", self.id_to_c(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_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, instr_attrib): + """Callback to generate code BEFORE the instruction execution + @instr_attrib: Attributes instance""" + + out = [] + + if instr_attrib.log_mn: + out.append( + 'printf("%.8X %s\\n");' % ( + instr_attrib.instr.offset, + instr_attrib.instr.to_string(self.lifter.loc_db) + ) + ) + return out + + def gen_post_code(self, attrib, pc_value): + """Callback to generate code AFTER the instruction execution + @attrib: Attributes instance""" + out = [] + if attrib.log_regs: + # Update PC for dump_gpregs + out.append("%s = %s;" % (self.C_PC, pc_value)) + out.append('dump_gpregs(jitcpu->cpu);') + return out + + 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 is_expr(dst): + out += self.gen_post_code(attrib, "DST_value") + 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.lifter.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, "0x%x" % offset) + out += self.gen_post_instr_checks(attrib) + out.append('goto %s;' % dst) + else: + out += self.gen_post_code(attrib, "0x%x" % offset) + 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_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(viewitems(dst2index), 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_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 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.lifter.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_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 gen_bad_block(self): + """ + Generate the C code for a bad_block instance + """ + return self.CODE_BAD_BLOCK.split("\n") + + 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.lifter.loc_db.get_or_create_offset_location(offset) + + 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.lifter.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 + """ + + 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_finalize(self, block): + """ + Generate the C code for the final block instruction + """ + + loc_key = self.get_block_post_label(block) + offset = self.lifter.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_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): + label = str(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, irblock) + + out += self.gen_finalize(block) + + return ['\t' + line for line in out] diff --git a/src/miasm/jitter/compat_py23.h b/src/miasm/jitter/compat_py23.h new file mode 100644 index 00000000..6dce7818 --- /dev/null +++ b/src/miasm/jitter/compat_py23.h @@ -0,0 +1,228 @@ +#ifndef __COMPAT_PY23_H__ +#define __COMPAT_PY23_H__ + + +#include "bn.h" + +#if PY_MAJOR_VERSION >= 3 +#define PyGetInt_uint_t(size_type, item, value) \ + if (PyLong_Check(item)) { \ + Py_INCREF(item); \ + PyObject* py_long = item; \ + PyObject* py_long_new; \ + bn_t bn; \ + uint64_t tmp; \ + int neg = 0; \ + \ + if (Py_SIZE(py_long) < 0) { \ + neg = 1; \ + py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \ + Py_DECREF(py_long); \ + py_long = py_long_new; \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \ + if (bignum_is_inf_equal_unsigned(mask_bn, bn)) { \ + RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \ + } \ + if (neg) { \ + bn = bignum_sub(mask_bn, bn); \ + } \ + tmp = bignum_to_uint64(bn); \ + value = (size_type) tmp; \ + } \ + else{ \ + RAISE(PyExc_TypeError, "Arg must be int"); \ + } + + +#define PyGetInt_uint_t_retneg(size_type, item, value) \ + if (PyLong_Check(item)) { \ + Py_INCREF(item); \ + PyObject* py_long = item; \ + PyObject* py_long_new; \ + bn_t bn; \ + uint64_t tmp; \ + int neg = 0; \ + \ + if (Py_SIZE(py_long) < 0) { \ + neg = 1; \ + py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \ + Py_DECREF(py_long); \ + py_long = py_long_new; \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \ + if (bignum_is_inf_equal_unsigned(mask_bn, bn)) { \ + PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \ + return -1; \ + } \ + if (neg) { \ + bn = bignum_sub(mask_bn, bn); \ + } \ + tmp = bignum_to_uint64(bn); \ + value = (size_type) tmp; \ + } \ + else{ \ + PyErr_SetString(PyExc_TypeError, "Arg must be int"); \ + return -1; \ + } + +#define PyGetStr(dest, name) \ + if (!PyUnicode_Check((name))) \ + RAISE(PyExc_TypeError,"Page name must be bytes"); \ + (dest) = PyUnicode_AsUTF8((name)) + + + +#else +#define PyGetInt_uint_t(size_type, item, value) \ + if (PyInt_Check(item)) { \ + long tmp; \ + tmp = PyInt_AsLong(item); \ + \ + if (Py_SIZE(item) < 0) { \ + if (-tmp > ((size_type) -1)) { \ + RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \ + } \ + } \ + else if (tmp > (size_type) -1) { \ + RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \ + } \ + value = (size_type) tmp; \ + } \ + else if (PyLong_Check(item)){ \ + Py_INCREF(item); \ + PyObject* py_long = item; \ + PyObject* py_long_new; \ + bn_t bn; \ + uint64_t tmp; \ + int neg = 0; \ + \ + if (Py_SIZE(py_long) < 0) { \ + neg = 1; \ + py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \ + Py_DECREF(py_long); \ + py_long = py_long_new; \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \ + if (bignum_is_inf_equal_unsigned(mask_bn, bn)) { \ + RAISE(PyExc_TypeError, "Arg too big for " #size_type ""); \ + } \ + if (neg) { \ + bn = bignum_sub(mask_bn, bn); \ + } \ + tmp = bignum_to_uint64(bn); \ + value = (size_type) tmp; \ + } \ + else{ \ + RAISE(PyExc_TypeError, "Arg must be int"); \ + } + + +#define PyGetInt_uint_t_retneg(size_type, item, value) \ + if (PyInt_Check(item)) { \ + long tmp; \ + tmp = PyInt_AsLong(item); \ + \ + if (Py_SIZE(item) < 0) { \ + if (-tmp > ((size_type) -1)) { \ + PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \ + return -1; \ + } \ + } \ + else if (tmp > (size_type) -1) { \ + PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \ + return -1; \ + } \ + value = (size_type) tmp; \ + } \ + else if (PyLong_Check(item)){ \ + Py_INCREF(item); \ + PyObject* py_long = item; \ + PyObject* py_long_new; \ + bn_t bn; \ + uint64_t tmp; \ + int neg = 0; \ + \ + if (Py_SIZE(py_long) < 0) { \ + neg = 1; \ + py_long_new = PyObject_CallMethod(py_long, "__neg__", NULL); \ + Py_DECREF(py_long); \ + py_long = py_long_new; \ + } \ + \ + bn = PyLong_to_bn(py_long); \ + \ + bn_t mask_bn = bignum_lshift(bignum_from_int(1), sizeof(size_type)*8); \ + if (bignum_is_inf_equal_unsigned(mask_bn, bn)) { \ + PyErr_SetString(PyExc_TypeError, "Arg too big for " #size_type ""); \ + return -1; \ + } \ + if (neg) { \ + bn = bignum_sub(mask_bn, bn); \ + } \ + tmp = bignum_to_uint64(bn); \ + value = (size_type) tmp; \ + } \ + else{ \ + PyErr_SetString(PyExc_TypeError, "Arg must be int"); \ + return -1; \ + } \ + + +#define PyGetStr(dest, name) \ + if (!PyString_Check((name))) \ + RAISE(PyExc_TypeError,"Page name must be bytes"); \ + (dest) = PyString_AsString((name)) + +#endif + + + +#define PyGetInt_size_t(item, value) PyGetInt_uint_t(size_t, item, value) + +#define PyGetInt_uint8_t(item, value) PyGetInt_uint_t(uint8_t, item, value) +#define PyGetInt_uint16_t(item, value) PyGetInt_uint_t(uint16_t, item, value) +#define PyGetInt_uint32_t(item, value) PyGetInt_uint_t(uint32_t, item, value) +#define PyGetInt_uint64_t(item, value) PyGetInt_uint_t(uint64_t, item, value) + +#define PyGetInt_uint8_t_retneg(item, value) PyGetInt_uint_t_retneg(uint8_t, item, value) +#define PyGetInt_uint16_t_retneg(item, value) PyGetInt_uint_t_retneg(uint16_t, item, value) +#define PyGetInt_uint32_t_retneg(item, value) PyGetInt_uint_t_retneg(uint32_t, item, value) +#define PyGetInt_uint64_t_retneg(item, value) PyGetInt_uint_t_retneg(uint64_t, item, value) + + + +#if PY_MAJOR_VERSION >= 3 + +#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) + +#define MOD_DEF(ob, name, doc, methods) \ + static struct PyModuleDef moduledef = { \ + PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ + ob = PyModule_Create(&moduledef); +#define RET_MODULE return module + +#else + +#define MOD_INIT(name) PyMODINIT_FUNC init##name(void) + +#define MOD_DEF(ob, name, doc, methods) \ + ob = Py_InitModule3(name, methods, doc); + +#define RET_MODULE return +#endif + + + + + +#endif diff --git a/src/miasm/jitter/csts.py b/src/miasm/jitter/csts.py new file mode 100644 index 00000000..f40cbe74 --- /dev/null +++ b/src/miasm/jitter/csts.py @@ -0,0 +1,50 @@ +#-*- coding:utf-8 -*- + + +# VM Mngr Exceptions +EXCEPT_DO_NOT_UPDATE_PC = 1 << 25 +EXCEPT_NUM_UPDT_EIP = (1<<11) + +EXCEPT_CODE_AUTOMOD = (1 << 0) +EXCEPT_SOFT_BP = (1 << 1) +EXCEPT_INT_XX = (1 << 2) +EXCEPT_SPR_ACCESS = (1 << 3) +EXCEPT_SYSCALL = (1 << 4) +EXCEPT_BREAKPOINT_MEMORY = (1 << 10) +# Deprecated +EXCEPT_BREAKPOINT_INTERN = EXCEPT_BREAKPOINT_MEMORY + +EXCEPT_ACCESS_VIOL = ((1 << 14) | EXCEPT_DO_NOT_UPDATE_PC) +EXCEPT_DIV_BY_ZERO = ((1 << 16) | EXCEPT_DO_NOT_UPDATE_PC) +EXCEPT_PRIV_INSN = ((1 << 17) | EXCEPT_DO_NOT_UPDATE_PC) +EXCEPT_ILLEGAL_INSN = ((1 << 18) | EXCEPT_DO_NOT_UPDATE_PC) +EXCEPT_UNK_MNEMO = ((1 << 19) | EXCEPT_DO_NOT_UPDATE_PC) +EXCEPT_INT_1 = ((1 << 20) | EXCEPT_DO_NOT_UPDATE_PC) + +JitterExceptions = { + "DO_NOT_UPDATE_PC": EXCEPT_DO_NOT_UPDATE_PC, + "NUM_UPDT_EIP": EXCEPT_NUM_UPDT_EIP, + "CODE_AUTOMOD": EXCEPT_CODE_AUTOMOD, + "SOFT_BP": EXCEPT_SOFT_BP, + "INT_XX": EXCEPT_INT_XX, + "SPR_ACCESS": EXCEPT_SPR_ACCESS, + "SYSCALL": EXCEPT_SYSCALL, + "BREAKPOINT_MEMORY": EXCEPT_BREAKPOINT_MEMORY, + "BREAKPOINT_INTERN": EXCEPT_BREAKPOINT_INTERN, + "ACCESS_VIOL": EXCEPT_ACCESS_VIOL, + "DIV_BY_ZERO": EXCEPT_DIV_BY_ZERO, + "PRIV_INSN": EXCEPT_PRIV_INSN, + "ILLEGAL_INSN": EXCEPT_ILLEGAL_INSN, + "UNK_MNEMO": EXCEPT_UNK_MNEMO, + "INT_1": EXCEPT_INT_1, +} + +# VM Mngr constants + +PAGE_READ = 1 +PAGE_WRITE = 2 +PAGE_EXEC = 4 + +BREAKPOINT_READ = 1 +BREAKPOINT_WRITE = 2 + diff --git a/src/miasm/jitter/emulatedsymbexec.py b/src/miasm/jitter/emulatedsymbexec.py new file mode 100644 index 00000000..1c3100ae --- /dev/null +++ b/src/miasm/jitter/emulatedsymbexec.py @@ -0,0 +1,170 @@ +from miasm.core.utils import decode_hex, encode_hex +import miasm.expression.expression as m2_expr +from miasm.ir.symbexec import SymbolicExecutionEngine +from miasm.arch.x86.arch import is_op_segm + + +class EmulatedSymbExec(SymbolicExecutionEngine): + """Symbolic exec instance linked with a jitter""" + + x86_cpuid = { + 0: { + 0: 0xa, + 1: 0x756E6547, + 2: 0x6C65746E, + 3: 0x49656E69, + }, + 1: { + 0: 0x00020652, + 1: 0x00000800, + 2: 0x00000209, + 3: 0x078bf9ff + }, + 2: { + 0: 0, + 1: 0, + 2: 0, + 3: 0 + }, + 4: { + 0: 0, + 1: 0, + 2: 0, + 3: 0 + }, + 7: { + 0: 0, + 1: (1 << 0) | (1 << 3), + 2: 0, + 3: 0 + }, + 0x80000000: { + 0: 0x80000008, + 1: 0, + 2: 0, + 3: 0 + }, + 0x80000001: { + 0: 0, + 1: 0, + 2: (1 << 0) | (1 << 8), + 3: (1 << 11) | (1 << 29), + }, + } + + def __init__(self, cpu, vm, *args, **kwargs): + """Instantiate an EmulatedSymbExec, associated to CPU @cpu and bind + memory accesses. + @cpu: JitCpu instance + """ + super(EmulatedSymbExec, self).__init__(*args, **kwargs) + self.cpu = cpu + self.vm = vm + + def reset_regs(self): + """Set registers value to 0. Ignore register aliases""" + for reg in self.lifter.arch.regs.all_regs_ids_no_alias: + self.symbols.symbols_id[reg] = m2_expr.ExprInt(0, size=reg.size) + + # Memory management + def mem_read(self, expr_mem): + """Memory read wrapper for symbolic execution + @expr_mem: ExprMem""" + + addr = expr_mem.ptr + if not addr.is_int(): + return super(EmulatedSymbExec, self).mem_read(expr_mem) + addr = int(addr) + size = expr_mem.size // 8 + value = self.vm.get_mem(addr, size) + if self.vm.is_little_endian(): + value = value[::-1] + self.vm.add_mem_read(addr, size) + + return m2_expr.ExprInt( + int(encode_hex(value), 16), + expr_mem.size + ) + + def mem_write(self, dest, data): + """Memory read wrapper for symbolic execution + @dest: ExprMem instance + @data: Expr instance""" + + # Get the content to write + data = self.expr_simp(data) + if not isinstance(data, m2_expr.ExprInt): + raise RuntimeError("A simplification is missing: %s" % data) + to_write = int(data) + + # Format information + addr = int(dest.ptr) + size = data.size // 8 + content = hex(to_write).replace("0x", "").replace("L", "") + content = "0" * (size * 2 - len(content)) + content + content = decode_hex(content) + + if self.vm.is_little_endian(): + content = content[::-1] + + # Write in VmMngr context + self.vm.set_mem(addr, content) + + # Interaction symbexec <-> jitter + def update_cpu_from_engine(self): + """Updates @cpu instance according to new CPU values""" + + for symbol in self.symbols: + if isinstance(symbol, m2_expr.ExprId): + if hasattr(self.cpu, symbol.name): + value = self.symbols.symbols_id[symbol] + if not isinstance(value, m2_expr.ExprInt): + raise ValueError("A simplification is missing: %s" % value) + + setattr(self.cpu, symbol.name, int(value)) + else: + raise NotImplementedError("Type not handled: %s" % symbol) + + + def update_engine_from_cpu(self): + """Updates CPU values according to @cpu instance""" + + for symbol in self.symbols: + if isinstance(symbol, m2_expr.ExprId): + if hasattr(self.cpu, symbol.name): + value = m2_expr.ExprInt(getattr(self.cpu, symbol.name), + symbol.size) + self.symbols.symbols_id[symbol] = value + else: + raise NotImplementedError("Type not handled: %s" % symbol) + + # CPU specific simplifications + def _simp_handle_segm(self, e_s, expr): + """Handle 'segm' operation""" + if not is_op_segm(expr): + return expr + if not expr.args[0].is_int(): + return expr + segm_nb = int(expr.args[0]) + segmaddr = self.cpu.get_segm_base(segm_nb) + return e_s(m2_expr.ExprInt(segmaddr, expr.size) + expr.args[1]) + + def _simp_handle_x86_cpuid(self, e_s, expr): + """From miasm/jitter/op_semantics.h: x86_cpuid""" + if expr.op != "x86_cpuid": + return expr + + if any(not arg.is_int() for arg in expr.args): + return expr + a, reg_num = (int(arg) for arg in expr.args) + + # Not found error is keeped on purpose + return m2_expr.ExprInt(self.x86_cpuid[a][reg_num], expr.size) + + def enable_emulated_simplifications(self): + """Enable simplifications needing a CPU instance on associated + ExpressionSimplifier + """ + self.expr_simp.enable_passes({ + m2_expr.ExprOp: [self._simp_handle_segm, self._simp_handle_x86_cpuid], + }) diff --git a/src/miasm/jitter/jitcore.py b/src/miasm/jitter/jitcore.py new file mode 100644 index 00000000..434854ca --- /dev/null +++ b/src/miasm/jitter/jitcore.py @@ -0,0 +1,308 @@ +from __future__ import print_function +# +# 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 hashlib import md5 +import warnings + +from future.utils import viewvalues + +from miasm.core.asmblock import disasmEngine, AsmBlockBad +from miasm.core.interval import interval +from miasm.core.utils import BoundedDict +from miasm.expression.expression import LocKey +from miasm.jitter.csts import * + +class JitCore(object): + + "JiT management. This is an abstract class" + + # Jitted function's name + FUNCNAME = "block_entry" + + jitted_block_delete_cb = None + jitted_block_max_size = 10000 + + def __init__(self, lifter, bin_stream): + """Initialise a JitCore instance. + @lifter: Lifter instance for current architecture + @bin_stream: bin_stream instance + """ + # Arch related + self.lifter = lifter + self.ircfg = self.lifter.new_ircfg() + self.arch_name = "%s%s" % (self.lifter.arch.name, self.lifter.attrib) + + # Structures for block tracking + self.offset_to_jitted_func = BoundedDict(self.jitted_block_max_size, + delete_cb=self.jitted_block_delete_cb) + self.loc_key_to_block = {} + self.blocks_mem_interval = interval() + + # Logging & options + self.log_mn = False + self.log_regs = False + self.log_newbloc = False + self.options = {"jit_maxline": 50, # Maximum number of line jitted + "max_exec_per_call": 0 # 0 means no limit + } + + # Disassembly Engine + self.split_dis = set() + self.mdis = disasmEngine( + lifter.arch, lifter.attrib, bin_stream, + lines_wd=self.options["jit_maxline"], + loc_db=lifter.loc_db, + follow_call=False, + dontdis_retcall=False, + split_dis=self.split_dis, + ) + + @property + def ir_arch(self): + warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"') + return self.lifter + + + def set_options(self, **kwargs): + "Set options relative to the backend" + self.options.update(kwargs) + + def clear_jitted_blocks(self): + "Reset all jitted blocks" + self.offset_to_jitted_func.clear() + self.loc_key_to_block.clear() + self.blocks_mem_interval = interval() + + 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): + "Initialise the Jitter" + raise NotImplementedError("Abstract class") + + def set_block_min_max(self, cur_block): + "Update cur_block to set min/max address" + + if cur_block.lines: + cur_block.ad_min = cur_block.lines[0].offset + cur_block.ad_max = cur_block.lines[-1].offset + cur_block.lines[-1].l + else: + # 1 byte block for unknown mnemonic + offset = self.lifter.loc_db.get_location_offset(cur_block.loc_key) + cur_block.ad_min = offset + cur_block.ad_max = offset+1 + + + def add_block_to_mem_interval(self, vm, block): + "Update vm to include block addresses in its memory range" + self.blocks_mem_interval += interval([(block.ad_min, block.ad_max - 1)]) + + vm.reset_code_bloc_pool() + for a, b in self.blocks_mem_interval: + vm.add_code_bloc(a, b + 1) + + def add_block(self, block): + """Add a block to JiT and JiT it. + @block: asm_bloc to add + """ + raise NotImplementedError("Abstract class") + + def disasm_and_jit_block(self, addr, vm): + """Disassemble a new block and JiT it + @addr: address of the block to disassemble (LocKey or int) + @vm: VmMngr instance + """ + + # Get the block + if isinstance(addr, LocKey): + addr = self.lifter.loc_db.get_location_offset(addr) + if addr is None: + raise RuntimeError("Unknown offset for LocKey") + + # Prepare disassembler + self.mdis.lines_wd = self.options["jit_maxline"] + + # Disassemble it + cur_block = self.mdis.dis_block(addr) + if isinstance(cur_block, AsmBlockBad): + return cur_block + # Logging + if self.log_newbloc: + print(cur_block) + + # Update label -> block + self.loc_key_to_block[cur_block.loc_key] = cur_block + + # Store min/max block address needed in jit automod code + self.set_block_min_max(cur_block) + + # JiT it + self.add_block(cur_block) + + # Update jitcode mem range + self.add_block_to_mem_interval(vm, cur_block) + return cur_block + + def run_at(self, cpu, offset, stop_offsets): + """Run from the starting address @offset. + Execution will stop if: + - max_exec_per_call option is reached + - a new, yet unknown, block is reached after the execution of block at + address @offset + - an address in @stop_offsets is reached + @cpu: JitCpu instance + @offset: starting address (int) + @stop_offsets: set of address on which the jitter must stop + """ + + if offset is None: + offset = getattr(cpu, self.lifter.pc.name) + + if offset not in self.offset_to_jitted_func: + # Need to JiT the block + cur_block = self.disasm_and_jit_block(offset, cpu.vmmngr) + if isinstance(cur_block, AsmBlockBad): + errno = cur_block.errno + if errno == AsmBlockBad.ERROR_IO: + cpu.vmmngr.set_exception(EXCEPT_ACCESS_VIOL) + elif errno == AsmBlockBad.ERROR_CANNOT_DISASM: + cpu.set_exception(EXCEPT_UNK_MNEMO) + else: + raise RuntimeError("Unhandled disasm result %r" % errno) + return offset + + # Run the block and update cpu/vmmngr state + return self.exec_wrapper(offset, cpu, self.offset_to_jitted_func.data, + stop_offsets, + self.options["max_exec_per_call"]) + + def blocks_to_memrange(self, blocks): + """Return an interval instance standing for blocks addresses + @blocks: list of AsmBlock instances + """ + + mem_range = interval() + mem_range = interval([(block.ad_min, block.ad_max - 1) for block in blocks]) + return mem_range + + def __updt_jitcode_mem_range(self, vm): + """Rebuild the VM blocks address memory range + @vm: VmMngr instance + """ + + # Reset the current pool + vm.reset_code_bloc_pool() + + # Add blocks in the pool + for start, stop in self.blocks_mem_interval: + vm.add_code_bloc(start, stop + 1) + + def del_block_in_range(self, ad1, ad2): + """Find and remove jitted block in range [ad1, ad2]. + Return the list of block removed. + @ad1: First address + @ad2: Last address + """ + + # Find concerned blocks + modified_blocks = set() + for block in viewvalues(self.loc_key_to_block): + if not block.lines: + continue + if block.ad_max <= ad1 or block.ad_min >= ad2: + # Block not modified + pass + else: + # Modified blocks + modified_blocks.add(block) + + # Remove modified blocks + for block in modified_blocks: + try: + for irblock in block.blocks: + # Remove offset -> jitted block link + offset = self.lifter.loc_db.get_location_offset(irblock.loc_key) + if offset in self.offset_to_jitted_func: + del(self.offset_to_jitted_func[offset]) + + except AttributeError: + # The block has never been translated in IR + offset = self.lifter.loc_db.get_location_offset(block.loc_key) + if offset in self.offset_to_jitted_func: + del(self.offset_to_jitted_func[offset]) + + # Remove label -> block link + del(self.loc_key_to_block[block.loc_key]) + + # Re generate blocks intervals + self.blocks_mem_interval = self.blocks_to_memrange(self.loc_key_to_block.values()) + + return modified_blocks + + def updt_automod_code_range(self, vm, mem_range): + """Remove jitted code in range @mem_range + @vm: VmMngr instance + @mem_range: list of start/stop addresses + """ + for addr_start, addr_stop in mem_range: + self.del_block_in_range(addr_start, addr_stop) + self.__updt_jitcode_mem_range(vm) + vm.reset_memory_access() + + def updt_automod_code(self, vm): + """Remove jitted code updated by memory write + @vm: VmMngr instance + """ + mem_range = [] + for addr_start, addr_stop in vm.get_memory_write(): + mem_range.append((addr_start, addr_stop)) + self.updt_automod_code_range(vm, mem_range) + + def hash_block(self, block): + """ + Build a hash of the block @block + @block: asmblock + """ + block_raw = b"".join(line.b for line in block.lines) + offset = self.lifter.loc_db.get_location_offset(block.loc_key) + block_hash = md5( + b"%X_%s_%s_%s_%s" % ( + offset, + self.arch_name.encode(), + b'\x01' if self.log_mn else b'\x00', + b'\x01' if self.log_regs else b'\x00', + block_raw + ) + ).hexdigest() + return block_hash + + @property + def disasm_cb(self): + warnings.warn("Deprecated API: use .mdis.dis_block_callback") + return self.mdis.dis_block_callback + + @disasm_cb.setter + def disasm_cb(self, value): + warnings.warn("Deprecated API: use .mdis.dis_block_callback") + self.mdis.dis_block_callback = value diff --git a/src/miasm/jitter/jitcore_cc_base.py b/src/miasm/jitter/jitcore_cc_base.py new file mode 100644 index 00000000..c5819d1f --- /dev/null +++ b/src/miasm/jitter/jitcore_cc_base.py @@ -0,0 +1,127 @@ +#-*- coding:utf-8 -*- + +import glob +import os +import tempfile +import platform +import sysconfig + +from miasm.jitter.jitcore import JitCore +from miasm.core.utils import keydefaultdict + +is_win = platform.system() == "Windows" + +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/op_semantics.h"\n' % lib_dir + txt += '#include "%s/vm_mngr.h"\n' % lib_dir + txt += '#include "%s/bn.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 + + +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_Cc_Base(JitCore): + "JiT management, abstract class using a C compiler as backend" + + def __init__(self, lifter, bin_stream): + self.jitted_block_delete_cb = self.deleteCB + super(JitCore_Cc_Base, self).__init__(lifter, bin_stream) + self.resolver = resolver() + self.lifter = lifter + self.states = {} + self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_cache") + try: + os.mkdir(self.tempdir, 0o755) + except OSError: + pass + if not os.access(self.tempdir, os.R_OK | os.W_OK): + raise RuntimeError( + 'Cannot access cache directory %s ' % self.tempdir) + self.exec_wrapper = None + self.libs = None + self.include_files = None + + def deleteCB(self, offset): + raise NotImplementedError() + + def load(self): + lib_dir = os.path.dirname(os.path.realpath(__file__)) + ext = sysconfig.get_config_var('EXT_SUFFIX') + if ext is None: + ext = ".so" if not is_win else ".lib" + if is_win: + # sysconfig.get_config_var('EXT_SUFFIX') is .pyd on Windows and need to be forced to .lib + # Additionally windows built libraries may have a name like VmMngr.cp38-win_amd64.lib + ext_files = glob.glob(os.path.join(lib_dir, "VmMngr.*lib")) + if len(ext_files) == 1: + ext = os.path.basename(ext_files[0]).replace("VmMngr", "") + + libs = [ + os.path.join(lib_dir, "VmMngr" + ext), + os.path.join( + lib_dir, + "arch", + "JitCore_%s%s" % (self.lifter.arch.name, ext) + ) + ] + + include_files = [ + os.path.dirname(__file__), + sysconfig.get_paths()['include'], + ] + self.include_files = include_files + self.libs = libs + + def init_codegen(self, codegen): + """ + Get the code generator @codegen + @codegen: an CGen instance + """ + self.codegen = codegen + + def gen_c_code(self, block): + """ + Return the C code corresponding to the @irblocks + @irblocks: list of irblocks + """ + f_declaration = '_MIASM_EXPORT int %s(block_id * BlockDst, JitCpu* jitcpu)' % self.FUNCNAME + out = self.codegen.gen_c( + block, + log_mn=self.log_mn, + log_regs=self.log_regs + ) + out = [f_declaration + '{'] + out + ['}\n'] + c_code = out + + return self.gen_C_source(self.lifter, c_code) + + @staticmethod + def gen_C_source(lifter, func_code): + raise NotImplementedError() diff --git a/src/miasm/jitter/jitcore_gcc.py b/src/miasm/jitter/jitcore_gcc.py new file mode 100644 index 00000000..958c9d13 --- /dev/null +++ b/src/miasm/jitter/jitcore_gcc.py @@ -0,0 +1,141 @@ +#-*- coding:utf-8 -*- + +import sys +import os +import tempfile +import ctypes +import _ctypes +import platform +import sysconfig +from subprocess import check_call +from miasm.jitter import Jitgcc +from miasm.jitter.jitcore_cc_base import JitCore_Cc_Base, gen_core + +is_win = platform.system() == "Windows" + +class JitCore_Gcc(JitCore_Cc_Base): + "JiT management, using a C compiler as backend" + + def __init__(self, lifter, bin_stream): + super(JitCore_Gcc, self).__init__(lifter, bin_stream) + self.exec_wrapper = Jitgcc.gcc_exec_block + + def deleteCB(self, offset): + """Free the state associated to @offset and delete it + @offset: gcc state offset + """ + flib = None + if is_win: + flib = _ctypes.FreeLibrary + else: + flib = _ctypes.dlclose + flib(self.states[offset]._handle) + del self.states[offset] + + def load_code(self, label, fname_so): + lib = ctypes.cdll.LoadLibrary(fname_so) + func = getattr(lib, self.FUNCNAME) + addr = ctypes.cast(func, ctypes.c_void_p).value + offset = self.lifter.loc_db.get_location_offset(label) + self.offset_to_jitted_func[offset] = addr + self.states[offset] = lib + + def add_block(self, block): + """Add a block to JiT and JiT it. + @block: block to jit + """ + block_hash = self.hash_block(block) + ext = sysconfig.get_config_var('EXT_SUFFIX') + if ext is None: + ext = ".so" if not is_win else ".pyd" + fname_out = os.path.join(self.tempdir, "%s%s" % (block_hash, ext)) + + if not os.access(fname_out, os.R_OK | os.X_OK): + func_code = self.gen_c_code(block) + + # Create unique C file + fdesc, fname_in = tempfile.mkstemp(suffix=".c") + os.write(fdesc, func_code.encode()) + os.close(fdesc) + + # Create unique SO file + fdesc, fname_tmp = tempfile.mkstemp(suffix=ext) + os.close(fdesc) + + inc_dir = ["-I%s" % inc for inc in self.include_files] + libs = ["%s" % lib for lib in self.libs] + if is_win: + libs.append( + os.path.join( + sysconfig.get_paths()['include'], + "..", + "libs", + "python%d%d.lib" % (sys.version_info.major, sys.version_info.minor) + ) + ) + cl = [ + "cl", "/nologo", "/W3", "/MP", + "/Od", "/DNDEBUG", "/D_WINDOWS", "/Gm-", "/EHsc", + "/RTC1", "/MD", "/GS", + fname_in + ] + inc_dir + libs + cl += ["/link", "/DLL", "/OUT:" + fname_tmp] + out_dir, _ = os.path.split(fname_tmp) + check_call(cl, cwd = out_dir) + basename_out, _ = os.path.splitext(fname_tmp) + basename_in, _ = os.path.splitext(os.path.basename(fname_in)) + for ext in ('.obj', '.exp', '.lib'): + artifact_out_path = os.path.join( + out_dir, + basename_out + ext + ) + if os.path.isfile(artifact_out_path): + os.remove(artifact_out_path) + artifact_in_path = os.path.join( + out_dir, + basename_in + ext + ) + if os.path.isfile(artifact_in_path): + os.remove(artifact_in_path) + else: + args = [ + "cc", + "-O3", + "-shared", + "-fPIC", + fname_in, + "-o", + fname_tmp + ] + inc_dir + libs + check_call(args) + + # Move temporary file to final file + try: + os.rename(fname_tmp, fname_out) + except WindowsError as e: + # On Windows, os.rename works slightly differently than on + # Linux; quoting the documentation: + # "On Unix, if dst exists and is a file, it will be replaced + # silently if the user has permission. The operation may fail + # on some Unix flavors if src and dst are on different + # filesystems. If successful, the renaming will be an atomic + # operation (this is a POSIX requirement). On Windows, if dst + # already exists, OSError will be raised even if it is a file; + # there may be no way to implement an atomic rename when dst + # names an existing file." + # [Error 183] Cannot create a file when that file already exists + if e.winerror != 183: + raise + os.remove(fname_tmp) + os.remove(fname_in) + + self.load_code(block.loc_key, fname_out) + + @staticmethod + def gen_C_source(lifter, func_code): + c_source = "" + c_source += "\n".join(func_code) + + c_source = gen_core(lifter.arch, lifter.attrib) + c_source + c_source = "#define PARITY_IMPORT\n#include <Python.h>\n" + c_source + return c_source diff --git a/src/miasm/jitter/jitcore_llvm.py b/src/miasm/jitter/jitcore_llvm.py new file mode 100644 index 00000000..4f1871b2 --- /dev/null +++ b/src/miasm/jitter/jitcore_llvm.py @@ -0,0 +1,144 @@ +from __future__ import print_function +import os +import glob +import importlib +import tempfile +import sysconfig + +from miasm.jitter.llvmconvert import * +import miasm.jitter.jitcore as jitcore +from miasm.jitter import Jitllvm +import platform + +import llvmlite +llvmlite.binding.load_library_permanently(Jitllvm.__file__) + +is_win = platform.system() == "Windows" + +class JitCore_LLVM(jitcore.JitCore): + "JiT management, using LLVM as backend" + + # Architecture dependent libraries + arch_dependent_libs = { + "x86": "JitCore_x86", + "arm": "JitCore_arm", + "msp430": "JitCore_msp430", + "mips32": "JitCore_mips32", + "aarch64": "JitCore_aarch64", + "ppc32": "JitCore_ppc32", + } + + def __init__(self, lifter, bin_stream): + super(JitCore_LLVM, self).__init__(lifter, bin_stream) + + self.options.update( + { + "safe_mode": True, # Verify each function + "optimise": True, # Optimise functions + "log_func": False, # Print LLVM functions + "log_assembly": False, # Print assembly executed + } + ) + + self.exec_wrapper = Jitllvm.llvm_exec_block + self.lifter = lifter + + # Cache temporary dir + self.tempdir = os.path.join(tempfile.gettempdir(), "miasm_cache") + try: + os.mkdir(self.tempdir, 0o755) + except OSError: + pass + if not os.access(self.tempdir, os.R_OK | os.W_OK): + raise RuntimeError( + 'Cannot access cache directory %s ' % self.tempdir) + + def load(self): + + # Library to load within Jit context + libs_to_load = [] + + # Get architecture dependent Jitcore library (if any) + lib_dir = os.path.dirname(os.path.realpath(__file__)) + ext = sysconfig.get_config_var('EXT_SUFFIX') + if ext is None: + ext = ".so" if not is_win else ".pyd" + if is_win: + # sysconfig.get_config_var('EXT_SUFFIX') is .pyd on Windows and need to be forced to .lib + # Additionally windows built libraries may have a name like VmMngr.cp38-win_amd64.lib + ext_files = glob.glob(os.path.join(lib_dir, "VmMngr.*pyd")) + if len(ext_files) == 1: + ext = os.path.basename(ext_files[0]).replace("VmMngr", "") + lib_dir = os.path.join(lib_dir, 'arch') + try: + jit_lib = os.path.join( + lib_dir, self.arch_dependent_libs[self.lifter.arch.name] + ext + ) + libs_to_load.append(jit_lib) + except KeyError: + pass + + # Create a context + self.context = LLVMContext_JIT(libs_to_load, self.lifter) + + # Set the optimisation level + self.context.optimise_level() + + # Save the current architecture parameters + self.arch = self.lifter.arch + + # Get the correspondence between registers and vmcpu struct + mod_name = "miasm.jitter.arch.JitCore_%s" % (self.lifter.arch.name) + mod = importlib.import_module(mod_name) + self.context.set_vmcpu(mod.get_gpreg_offset_all()) + + # Enable caching + self.context.enable_cache() + + def add_block(self, block): + """Add a block to JiT and JiT it. + @block: the block to add + """ + + block_hash = self.hash_block(block) + fname_out = os.path.join(self.tempdir, "%s.bc" % block_hash) + + if not os.access(fname_out, os.R_OK): + # Build a function in the context + func = LLVMFunction(self.context, self.FUNCNAME) + + # Set log level + func.log_regs = self.log_regs + func.log_mn = self.log_mn + + # Import asm block + func.from_asmblock(block) + + # Verify + if self.options["safe_mode"] is True: + func.verify() + + # Optimise + if self.options["optimise"] is True: + func.optimise() + + # Log + if self.options["log_func"] is True: + print(func) + if self.options["log_assembly"] is True: + print(func.get_assembly()) + + # Use propagate the cache filename + self.context.set_cache_filename(func, fname_out) + + # Get a pointer on the function for JiT + ptr = func.get_function_pointer() + + else: + # The cache file exists: function can be loaded from cache + ptr = self.context.get_ptr_from_cache(fname_out, self.FUNCNAME) + + # Store a pointer on the function jitted code + loc_key = block.loc_key + offset = self.lifter.loc_db.get_location_offset(loc_key) + self.offset_to_jitted_func[offset] = ptr diff --git a/src/miasm/jitter/jitcore_python.py b/src/miasm/jitter/jitcore_python.py new file mode 100644 index 00000000..269df973 --- /dev/null +++ b/src/miasm/jitter/jitcore_python.py @@ -0,0 +1,219 @@ +from __future__ import print_function +from builtins import zip +import miasm.jitter.jitcore as jitcore +from miasm.expression.expression import ExprInt, ExprLoc +import miasm.jitter.csts as csts +from miasm.expression.simplifications import expr_simp_explicit +from miasm.jitter.emulatedsymbexec import EmulatedSymbExec + +################################################################################ +# Python jitter Core # +################################################################################ + + +class JitCore_Python(jitcore.JitCore): + "JiT management, using Miasm2 Symbol Execution engine as backend" + + SymbExecClass = EmulatedSymbExec + + def __init__(self, lifter, bin_stream): + super(JitCore_Python, self).__init__(lifter, bin_stream) + self.lifter = lifter + self.ircfg = self.lifter.new_ircfg() + + # CPU & VM (None for now) will be set later + + self.symbexec = self.SymbExecClass( + None, None, + self.lifter, {}, + sb_expr_simp=expr_simp_explicit + ) + self.symbexec.enable_emulated_simplifications() + + def set_cpu_vm(self, cpu, vm): + self.symbexec.cpu = cpu + self.symbexec.vm = vm + + def load(self): + "Preload symbols according to current architecture" + self.symbexec.reset_regs() + + def arch_specific(self): + """Return arch specific information for the current architecture""" + arch = self.lifter.arch + has_delayslot = False + if arch.name == "mips32": + from miasm.arch.mips32.jit import mipsCGen + cgen_class = mipsCGen + has_delayslot = True + elif arch.name == "arm": + from miasm.arch.arm.jit import arm_CGen + cgen_class = arm_CGen + else: + from miasm.jitter.codegen import CGen + cgen_class = CGen + return cgen_class(self.lifter), 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.lifter.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 + """ + # Get virtual memory handler + vmmngr = cpu.vmmngr + + # Get execution engine (EmulatedSymbExec instance) + exec_engine = self.symbexec + + # Refresh CPU values according to @cpu instance + exec_engine.update_engine_from_cpu() + + # Get initial loc_key + cur_loc_key = asmblock.loc_key + + # Update PC helper + update_pc = lambda value: setattr(cpu, self.lifter.pc.name, value) + + 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.lifter.irbloc_fix_regs_for_mode( + irblock, self.lifter.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] + + # Eval current instruction (in IR) + exec_engine.eval_updt_assignblk(assignblk) + + # 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 + + # Update registers values + exec_engine.update_cpu_from_engine() + + # 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 + + dst = exec_engine.eval_expr(self.lifter.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.lifter.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 (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 = loc_db.get_location_offset(asmblock.loc_key) + assert offset is not None + self.offset_to_jitted_func[offset] = myfunc + + def exec_wrapper(self, loc_key, cpu, _offset_to_jitted_func, _stop_offsets, + _max_exec_per_call): + """Call the function @loc_key with @cpu + @loc_key: function's loc_key + @cpu: JitCpu instance + """ + + # Get Python function corresponding to @loc_key + fc_ptr = self.offset_to_jitted_func[loc_key] + + # Execute the function + return fc_ptr(cpu) diff --git a/src/miasm/jitter/jitload.py b/src/miasm/jitter/jitload.py new file mode 100644 index 00000000..99e4429d --- /dev/null +++ b/src/miasm/jitter/jitload.py @@ -0,0 +1,585 @@ +import logging +import warnings +from functools import wraps +from collections import namedtuple +try: + from collections.abc import Sequence, Iterator +except ImportError: + from collections import Sequence, Iterator + +from future.utils import viewitems + +from miasm.jitter.csts import * +from miasm.core.utils import * +from miasm.core.bin_stream import bin_stream_vm +from miasm.jitter.emulatedsymbexec import EmulatedSymbExec +from miasm.jitter.codegen import CGen +from miasm.jitter.jitcore_cc_base import JitCore_Cc_Base + +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log = logging.getLogger('jitload.py') +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) +log_func = logging.getLogger('jit function call') +log_func.addHandler(hnd) +log_func.setLevel(logging.CRITICAL) + +try: + from miasm.jitter import VmMngr +except ImportError: + log.error('cannot import VmMngr') + + +def named_arguments(func): + """Function decorator to allow the use of .func_args_*() methods + with either the number of arguments or the list of the argument + names. + + The wrapper is also used to log the argument values. + + @func: function + + """ + @wraps(func) + def newfunc(self, args): + if isinstance(args, Sequence): + ret_ad, arg_vals = func(self, len(args)) + arg_vals = namedtuple("args", args)(*arg_vals) + # func_name(arguments) return address + log_func.info( + '%s(%s) ret addr: %s', + get_caller_name(1), + ', '.join( + "%s=0x%x" % (field, value) + for field, value in viewitems(arg_vals._asdict()) + ), + hex(ret_ad) + ) + return ret_ad, namedtuple("args", args)(*arg_vals) + else: + ret_ad, arg_vals = func(self, args) + # func_name(arguments) return address + log_func.info('%s(%s) ret addr: %s', + get_caller_name(1), + ', '.join(hex(arg) for arg in arg_vals), + hex(ret_ad)) + return ret_ad, arg_vals + return newfunc + + +class CallbackHandler(object): + + "Handle a list of callback" + + def __init__(self): + self.callbacks = {} # Key -> [callback list] + + def add_callback(self, key, callback): + """Add a callback to the key @key, iff the @callback isn't already + assigned to it""" + if callback not in self.callbacks.get(key, []): + self.callbacks[key] = self.callbacks.get(key, []) + [callback] + + def set_callback(self, key, *args): + "Set the list of callback for key 'key'" + self.callbacks[key] = list(args) + + def get_callbacks(self, key): + "Return the list of callbacks associated to key 'key'" + return self.callbacks.get(key, []) + + def remove_callback(self, callback): + """Remove the callback from the list. + Return the list of empty keys (removed)""" + + to_check = set() + for key, cb_list in viewitems(self.callbacks): + try: + cb_list.remove(callback) + to_check.add(key) + except ValueError: + pass + + empty_keys = [] + for key in to_check: + if len(self.callbacks[key]) == 0: + empty_keys.append(key) + del(self.callbacks[key]) + + return empty_keys + + def has_callbacks(self, key): + return key in self.callbacks + + def remove_key(self, key): + """Remove and return all callbacks associated to @key""" + callbacks = self.callbacks.get(key, []) + del self.callbacks[key] + return callbacks + + def call_callbacks(self, key, *args): + """Call callbacks associated to key 'key' with arguments args. While + callbacks return True, continue with next callback. + Iterator on other results.""" + + res = True + + for c in self.get_callbacks(key): + res = c(*args) + if res is not True: + yield res + + def __call__(self, key, *args): + "Wrapper for call_callbacks" + return self.call_callbacks(key, *args) + + +class CallbackHandlerBitflag(CallbackHandler): + + "Handle a list of callback with conditions on bitflag" + + def call_callbacks(self, bitflag, *args): + """Call each callbacks associated with bit set in bitflag. While + callbacks return True, continue with next callback. + Iterator on other results""" + + for bitflag_expected in self.callbacks: + if bitflag_expected & bitflag == bitflag_expected: + # If the flag matched + for res in super(CallbackHandlerBitflag, + self).call_callbacks(bitflag_expected, *args): + if res is not True: + yield res + + +class ExceptionHandle(object): + + "Return type for exception handler" + + def __init__(self, except_flag): + self.except_flag = except_flag + + @classmethod + def memoryBreakpoint(cls): + return cls(EXCEPT_BREAKPOINT_MEMORY) + + def __eq__(self, to_cmp): + if not isinstance(to_cmp, ExceptionHandle): + return False + return (self.except_flag == to_cmp.except_flag) + + def __ne__(self, to_cmp): + return not self.__eq__(to_cmp) + + +class JitterException(Exception): + + "Raised when any unhandled exception occurs (in jitter.vm or jitter.cpu)" + + def __init__(self, exception_flag): + super(JitterException, self).__init__() + self.exception_flag = exception_flag + + def __str__(self): + return "A jitter exception occurred: %s (0x%x)" % ( + self.exception_flag_to_str(), self.exception_flag + ) + + def exception_flag_to_str(self): + exception_flag_list = [] + for name, value in JitterExceptions.items(): + if value & self.exception_flag == value: + exception_flag_list.append(name) + return ' & '.join(exception_flag_list) + + +class Jitter(object): + + "Main class for JIT handling" + + C_Gen = CGen + + def __init__(self, lifter, jit_type="gcc"): + """Init an instance of jitter. + @lifter: Lifter instance for this architecture + @jit_type: JiT backend to use. Available options are: + - "gcc" + - "llvm" + - "python" + """ + + self.arch = lifter.arch + self.attrib = lifter.attrib + arch_name = lifter.arch.name # (lifter.arch.name, lifter.attrib) + self.running = False + + try: + if arch_name == "x86": + from miasm.jitter.arch import JitCore_x86 as jcore + elif arch_name == "arm": + from miasm.jitter.arch import JitCore_arm as jcore + elif arch_name == "armt": + from miasm.jitter.arch import JitCore_arm as jcore + lifter.arch.name = 'arm' + elif arch_name == "aarch64": + from miasm.jitter.arch import JitCore_aarch64 as jcore + elif arch_name == "msp430": + from miasm.jitter.arch import JitCore_msp430 as jcore + elif arch_name == "mips32": + from miasm.jitter.arch import JitCore_mips32 as jcore + elif arch_name == "ppc32": + from miasm.jitter.arch import JitCore_ppc32 as jcore + elif arch_name == "mep": + from miasm.jitter.arch import JitCore_mep 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() + self.lifter = lifter + self.bs = bin_stream_vm(self.vm) + self.ircfg = self.lifter.new_ircfg() + + self.symbexec = EmulatedSymbExec( + self.cpu, self.vm, self.lifter, {} + ) + self.symbexec.reset_regs() + + try: + if jit_type == "llvm": + from miasm.jitter.jitcore_llvm import JitCore_LLVM as JitCore + elif jit_type == "python": + from miasm.jitter.jitcore_python import JitCore_Python as JitCore + elif jit_type == "gcc": + from miasm.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.lifter, self.bs) + if isinstance(self.jit, JitCore_Cc_Base): + self.jit.init_codegen(self.C_Gen(self.lifter)) + elif jit_type == "python": + self.jit.set_cpu_vm(self.cpu, self.vm) + + self.cpu.init_regs() + self.vm.init_memory_page_pool() + self.vm.init_code_bloc_pool() + self.vm.init_memory_breakpoint() + + self.jit.load() + self.cpu.vmmngr = self.vm + self.cpu.jitter = self.jit + self.stack_size = 0x10000 + self.stack_base = 0x1230000 + + # Init callback handler + self.breakpoints_handler = CallbackHandler() + self.exceptions_handler = CallbackHandlerBitflag() + self.init_exceptions_handler() + self.exec_cb = None + + 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 + + self.add_exception_handler(EXCEPT_CODE_AUTOMOD, exception_automod) + + 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 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 get_breakpoint(self, addr): + """ + Return breakpoints handlers for address @addr + @addr: integer + """ + return self.breakpoints_handler.get_callbacks(addr) + + 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 remove_breakpoints_by_address(self, address): + """Remove all breakpoints associated with @address. + @address: address of breakpoints to remove + """ + callbacks = self.breakpoints_handler.remove_key(address) + if callbacks: + self.jit.remove_disassembly_splits(address) + + 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 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) + ) + + 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, 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, 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 + exception_flag = self.get_exception() + if exception_flag: + raise JitterException(exception_flag) + + # Run the block 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, Iterator): + for tmp in res: + yield tmp + else: + yield res + + def init_run(self, pc): + """Create an iterator on pc with runiter. + @pc: address of code to run + """ + self.run_iterator = self.runiter_once(pc) + self.pc = pc + self.running = True + + def continue_run(self, step=False, trace=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. + If trace is True, activate trace log option until execution stops + Return the iterator value""" + + if trace: + self.set_trace_log() + while self.running: + try: + return next(self.run_iterator) + except StopIteration: + pass + + self.run_iterator = self.runiter_once(self.pc) + + if step is True: + break + if trace: + self.set_trace_log(False, False, False) + return None + + + def run(self, addr): + """ + Launch emulation + @addr: (int) start address + """ + self.init_run(addr) + return self.continue_run() + + def run_until(self, addr, trace=False): + """PRE: init_run. + Continue the run of the current session until iterator returns, run is + set to False or addr is reached. + If trace is True, activate trace log option until execution stops + Return the iterator value""" + + def stop_exec(jitter): + jitter.remove_breakpoints_by_callback(stop_exec) + return False + self.add_breakpoint(addr, stop_exec) + return self.continue_run(trace=trace) + + def init_stack(self): + self.vm.add_memory_page( + self.stack_base, + PAGE_READ | PAGE_WRITE, + b"\x00" * self.stack_size, + "Stack") + sp = self.arch.getsp(self.attrib) + setattr(self.cpu, sp.name, self.stack_base + self.stack_size) + # regs = self.cpu.get_gpreg() + # regs[sp.name] = self.stack_base+self.stack_size + # self.cpu.set_gpreg(regs) + + def get_exception(self): + return self.cpu.get_exception() | self.vm.get_exception() + + # common functions + def get_c_str(self, addr, max_char=None): + """Get C 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) != b"\x00"): + tmp += 1 + l += 1 + value = self.vm.get_mem(addr, l) + value = force_str(value) + return value + + def set_c_str(self, addr, value): + """Set C str str from vm. + @addr: address in memory + @value: str""" + value = force_bytes(value) + self.vm.set_mem(addr, value + b'\x00') + + def get_str_ansi(self, addr, max_char=None): + raise NotImplementedError("Deprecated: use os_dep.win_api_x86_32.get_win_str_a") + + def get_str_unic(self, addr, max_char=None): + raise NotImplementedError("Deprecated: use os_dep.win_api_x86_32.get_win_str_a") + + @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.lifter.pc.name) + + # Don't break on a None return + if ret is None: + return True + else: + return ret + + def handle_function(self, f_addr): + """Add a breakpoint which will trigger the function handler""" + self.add_breakpoint(f_addr, self.handle_lib) + + 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 + out = {} + for name, func in viewitems(user_globals): + out[name] = func + self.user_globals = out + + for f_addr in libs.fad2cname: + self.handle_function(f_addr) + + 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 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(Jitter): + """ + DEPRECATED object + Use Jitter instead of jitter + """ + + + def __init__(self, *args, **kwargs): + warnings.warn("Deprecated API: use Jitter") + super(jitter, self).__init__(*args, **kwargs) diff --git a/src/miasm/jitter/llvmconvert.py b/src/miasm/jitter/llvmconvert.py new file mode 100644 index 00000000..2430d884 --- /dev/null +++ b/src/miasm/jitter/llvmconvert.py @@ -0,0 +1,1935 @@ +# +# +# Miasm2 Extension: # +# - Miasm2 IR to LLVM IR # +# - JiT # +# +# Requires: # +# - llvmlite (tested on v0.15) # +# +# Authors : Fabrice DESCLAUX (CEA/DAM), Camille MOUGEY (CEA/DAM) # +# +# + +from builtins import zip +from builtins import range +import os +from llvmlite import binding as llvm +from llvmlite import ir as llvm_ir +from builtins import int as int_types +import warnings + +from future.utils import viewitems, viewvalues + +from miasm.expression.expression import ExprId, ExprInt, ExprMem, ExprSlice, \ + ExprCond, ExprLoc, ExprOp, ExprCompose, LocKey, Expr, \ + TOK_EQUAL, \ + TOK_INF_SIGNED, TOK_INF_UNSIGNED, \ + TOK_INF_EQUAL_SIGNED, TOK_INF_EQUAL_UNSIGNED + +import miasm.jitter.csts as m2_csts +import miasm.core.asmblock as m2_asmblock +from miasm.core.utils import size2mask +from miasm.jitter.codegen import CGen, Attributes +from miasm.expression.expression_helper import possible_values + + +class LLVMType(llvm_ir.Type): + + "Handle LLVM Type" + + int_cache = {} + + @classmethod + def IntType(cls, size=32): + try: + return cls.int_cache[size] + except KeyError: + cls.int_cache[size] = llvm_ir.IntType(size) + return cls.int_cache[size] + + @classmethod + def pointer(cls, addr): + "Generic pointer for execution" + return llvm_e.GenericValue.pointer(addr) + + @classmethod + def generic(cls, e): + "Generic value for execution" + if isinstance(e, ExprInt): + return llvm_e.GenericValue.int(LLVMType.IntType(e.size), int(e.arg)) + elif isinstance(e, llvm_e.GenericValue): + return e + else: + raise ValueError() + + @classmethod + def fptype(cls, size): + """Return the floating type corresponding to precision @size""" + if size == 32: + precision = llvm_ir.FloatType() + elif size == 64: + precision = llvm_ir.DoubleType() + else: + raise RuntimeError("Unsupported precision: %x", size) + return precision + + +class LLVMContext(object): + + "Context for llvm binding. Stand for a LLVM Module" + + known_fc = {} + + def __init__(self, name="mod"): + "Initialize a context with a module named 'name'" + # Initialize llvm + llvm.initialize() + llvm.initialize_native_target() + llvm.initialize_native_asmprinter() + + # Initialize target for compilation + target = llvm.Target.from_default_triple() + self.target_machine = target.create_target_machine() + self.init_exec_engine() + + def canonize_label_name(self, label): + """Canonize @label names to a common form. + @label: str or asmlabel instance""" + if isinstance(label, str): + return label + elif isinstance(label, LocKey): + return str(label) + else: + raise ValueError("label must either be str or LocKey") + + def optimise_level(self, level=2): + """Set the optimisation level to @level from 0 to 2 + 0: non-optimized + 2: optimized + """ + + # Set up the optimiser pipeline + pmb = llvm.create_pass_manager_builder() + pmb.opt_level = level + pm = llvm.create_module_pass_manager() + pmb.populate(pm) + self.pass_manager = pm + + def init_exec_engine(self): + mod = llvm.parse_assembly("") + engine = llvm.create_mcjit_compiler(mod, + self.target_machine) + self.exec_engine = engine + + def new_module(self, name="mod"): + """Create a module, with needed functions""" + self.mod = llvm_ir.Module(name=name) + self.add_fc(self.known_fc) + self.add_op() + + def get_execengine(self): + "Return the Execution Engine associated with this context" + return self.exec_engine + + def get_passmanager(self): + "Return the Pass Manager associated with this context" + return self.pass_manager + + def get_module(self): + "Return the module associated with this context" + return self.mod + + def add_shared_library(self, filename): + "Load the shared library 'filename'" + return llvm.load_library_permanently(filename) + + def add_fc(self, fc, readonly=False): + "Add function into known_fc" + + for name, detail in viewitems(fc): + fnty = llvm_ir.FunctionType(detail["ret"], detail["args"]) + fn = llvm_ir.Function(self.mod, fnty, name=name) + if readonly: + fn.attributes.add("readonly") + + def add_op(self): + "Add operations functions" + + i8 = LLVMType.IntType(8) + p8 = llvm_ir.PointerType(i8) + itype = LLVMType.IntType(64) + ftype = llvm_ir.FloatType() + dtype = llvm_ir.DoubleType() + fc = {"llvm.ctpop.i8": {"ret": i8, + "args": [i8]}, + "llvm.nearbyint.f32": {"ret": ftype, + "args": [ftype]}, + "llvm.nearbyint.f64": {"ret": dtype, + "args": [dtype]}, + "llvm.trunc.f32": {"ret": ftype, + "args": [ftype]}, + "segm2addr": {"ret": itype, + "args": [p8, + itype, + itype]}, + "x86_cpuid": {"ret": itype, + "args": [itype, + itype]}, + "fpu_fcom_c0": {"ret": itype, + "args": [dtype, + dtype]}, + "fpu_fcom_c1": {"ret": itype, + "args": [dtype, + dtype]}, + "fpu_fcom_c2": {"ret": itype, + "args": [dtype, + dtype]}, + "fpu_fcom_c3": {"ret": itype, + "args": [dtype, + dtype]}, + "llvm.sqrt.f32": {"ret": ftype, + "args": [ftype]}, + "llvm.sqrt.f64": {"ret": dtype, + "args": [dtype]}, + "llvm.fabs.f32": {"ret": ftype, + "args": [ftype]}, + "llvm.fabs.f64": {"ret": dtype, + "args": [dtype]}, + } + + for k in [8, 16]: + fc["bcdadd_%s" % k] = {"ret": LLVMType.IntType(k), + "args": [LLVMType.IntType(k), + LLVMType.IntType(k)]} + fc["bcdadd_cf_%s" % k] = {"ret": LLVMType.IntType(k), + "args": [LLVMType.IntType(k), + LLVMType.IntType(k)]} + self.add_fc(fc, readonly=True) + + + def memory_lookup(self, func, addr, size): + """Perform a memory lookup at @addr of size @size (in bit)""" + raise NotImplementedError("Abstract method") + + def memory_write(self, func, addr, size, value): + """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value""" + raise NotImplementedError("Abstract method") + + +class LLVMContext_JIT(LLVMContext): + + """Extend LLVMContext_JIT in order to handle memory management and custom + operations""" + + def __init__(self, library_filenames, lifter, name="mod"): + "Init a LLVMContext object, and load the mem management shared library" + self.library_filenames = library_filenames + self.lifter = lifter + self.arch_specific() + self.load_libraries() + LLVMContext.__init__(self, name) + self.vmcpu = {} + + @property + def ir_arch(self): + warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"') + return self.lifter + + def load_libraries(self): + # Get LLVM specific functions + name = "libLLVM-%d.%d" % (llvm.llvm_version_info[0], + llvm.llvm_version_info[1], + ) + try: + # On Windows, no need to add ".dll" + self.add_shared_library(name) + except RuntimeError: + try: + # On Linux, ".so" is needed + self.add_shared_library("%s.so" % name) + except RuntimeError: + pass + + # Load additional libraries + for lib_fname in self.library_filenames: + self.add_shared_library(lib_fname) + + def new_module(self, name="mod"): + LLVMContext.new_module(self, name) + self.add_memlookups() + self.add_get_exceptionflag() + self.add_log_functions() + + def arch_specific(self): + arch = self.lifter.arch + if arch.name == "x86": + self.PC = arch.regs.RIP + self.logging_func = "dump_gpregs_%d" % self.lifter.attrib + else: + self.PC = self.lifter.pc + self.logging_func = "dump_gpregs" + if arch.name == "mips32": + from miasm.arch.mips32.jit import mipsCGen + self.cgen_class = mipsCGen + self.has_delayslot = True + elif arch.name == "arm": + from miasm.arch.arm.jit import arm_CGen + self.cgen_class = arm_CGen + self.has_delayslot = False + else: + self.cgen_class = CGen + self.has_delayslot = False + + def add_memlookups(self): + "Add MEM_LOOKUP functions" + + fc = {} + p8 = llvm_ir.PointerType(LLVMType.IntType(8)) + for i in [8, 16, 32, 64]: + fc["MEM_LOOKUP_%02d" % i] = {"ret": LLVMType.IntType(i), + "args": [p8, + LLVMType.IntType(64)]} + + fc["MEM_WRITE_%02d" % i] = {"ret": llvm_ir.VoidType(), + "args": [p8, + LLVMType.IntType(64), + LLVMType.IntType(i)]} + + fc["MEM_LOOKUP_INT_BN_TO_PTR"] = {"ret": llvm_ir.VoidType(), + "args": [ + p8, + LLVMType.IntType(32), + LLVMType.IntType(64), + p8 + ]} + fc["MEM_WRITE_INT_BN_FROM_PTR"] = {"ret": llvm_ir.VoidType(), + "args": [ + p8, + LLVMType.IntType(32), + LLVMType.IntType(64), + p8, + ]} + + fc["reset_memory_access"] = {"ret": llvm_ir.VoidType(), + "args": [p8, + ]} + fc["check_memory_breakpoint"] = {"ret": llvm_ir.VoidType(), + "args": [p8, + ]} + fc["check_invalid_code_blocs"] = {"ret": llvm_ir.VoidType(), + "args": [p8, + ]} + self.add_fc(fc) + + def add_get_exceptionflag(self): + "Add 'get_exception_flag' function" + p8 = llvm_ir.PointerType(LLVMType.IntType(8)) + self.add_fc({"get_exception_flag": {"ret": LLVMType.IntType(64), + "args": [p8]}}, readonly=True) + + def add_log_functions(self): + "Add functions for state logging" + + p8 = llvm_ir.PointerType(LLVMType.IntType(8)) + self.add_fc({self.logging_func: {"ret": llvm_ir.VoidType(), + "args": [p8]}}, + readonly=True) + + def set_vmcpu(self, lookup_table): + "Set the correspondence between register name and vmcpu offset" + + self.vmcpu = lookup_table + + def memory_lookup(self, func, addr, size): + """Perform a memory lookup at @addr of size @size (in bit)""" + builder = func.builder + if size <= 64: + fc_name = "MEM_LOOKUP_%02d" % size + fc_ptr = self.mod.get_global(fc_name) + addr_casted = builder.zext(addr, LLVMType.IntType(64)) + ret = builder.call( + fc_ptr, [func.local_vars["jitcpu"],addr_casted] + ) + else: + # Miasm uses a memory lookup function which returns a bn_t for its + # result. We cannot simply translate this into IntType. The trick + # here is to use the function MEM_LOOKUP_INT_BN_TO_PTR which has a + # different interface: the resulting bn_t is passed through a char* + # argument. + # + # WARNING: Here, we use the fact that the serialisation of LLVM + # IntType is the *same* as the bn_t structure. + + fc_name = "MEM_LOOKUP_INT_BN_TO_PTR" + fc_ptr = self.mod.get_global(fc_name) + addr_casted = builder.zext(addr, LLVMType.IntType(64)) + size_cst = llvm_ir.Constant(LLVMType.IntType(32), size) + + value_ptr = builder.alloca(llvm_ir.IntType(size)) + value_ptr_u8 = builder.bitcast( + value_ptr, + LLVMType.IntType(8).as_pointer() + ) + + + builder.call( + fc_ptr, + [ + func.local_vars["jitcpu"], + size_cst, + addr_casted, + value_ptr_u8 + ] + ) + ret = builder.load(value_ptr) + + return ret + + def memory_write(self, func, addr, size, value): + """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value""" + # Function call + builder = func.builder + if size <= 64: + fc_name = "MEM_WRITE_%02d" % size + fc_ptr = self.mod.get_global(fc_name) + dst_casted = builder.zext(addr, LLVMType.IntType(64)) + builder.call( + fc_ptr, + [ + func.local_vars["jitcpu"], + dst_casted, + value + ] + ) + else: + # The same trick as described in MEM_LOOKUP_INT_BN_TO_PTR is used + # here. + + fc_name = "MEM_WRITE_INT_BN_FROM_PTR" + fc_ptr = self.mod.get_global(fc_name) + addr_casted = builder.zext(addr, LLVMType.IntType(64)) + size_cst = llvm_ir.Constant(LLVMType.IntType(32), size) + + ret = builder.alloca(value.type) + builder.store(value, ret) + value_ptr = builder.bitcast(ret, llvm_ir.IntType(8).as_pointer()) + + builder.call( + fc_ptr, + [ + func.local_vars["jitcpu"], + size_cst, + addr_casted, + value_ptr, + ] + ) + + + @staticmethod + def cache_notify(module, buffer): + """Called when @module has been compiled to @buffer""" + if not hasattr(module, "fname_out"): + return + fname_out = module.fname_out + + if os.access(fname_out, os.R_OK): + # No need to overwrite + return + + open(fname_out, "wb").write(buffer) + + @staticmethod + def cache_getbuffer(module): + """Return a compiled buffer for @module if available""" + if not hasattr(module, "fname_out"): + return None + + fname_out = module.fname_out + if os.access(fname_out, os.R_OK): + return open(fname_out, "rb").read() + return None + + def enable_cache(self): + "Enable cache of compiled object" + # Load shared libraries + for lib_fname in self.library_filenames: + self.add_shared_library(lib_fname) + + # Activate cache + self.exec_engine.set_object_cache( + self.cache_notify, + self.cache_getbuffer + ) + + def set_cache_filename(self, func, fname_out): + "Set the filename @fname_out to use for cache for @func" + # Use a custom attribute to propagate the cache filename + func.as_llvm_mod().fname_out = fname_out + + def get_ptr_from_cache(self, file_name, func_name): + "Load @file_name and return a pointer on the jitter @func_name" + # We use an empty module to avoid losing time on function building + empty_module = llvm.parse_assembly("") + empty_module.fname_out = file_name + + engine = self.exec_engine + engine.add_module(empty_module) + engine.finalize_object() + return engine.get_function_address(func_name) + + +class LLVMContext_IRCompilation(LLVMContext): + + """Extend LLVMContext in order to handle memory management and custom + operations for Miasm IR compilation""" + + def memory_lookup(self, func, addr, size): + """Perform a memory lookup at @addr of size @size (in bit)""" + builder = func.builder + int_size = LLVMType.IntType(size) + ptr_casted = builder.inttoptr( + addr, + llvm_ir.PointerType(int_size) + ) + return builder.load(ptr_casted) + + def memory_write(self, func, addr, size, value): + """Perform a memory write at @addr of size @size (in bit) with LLVM IR @value""" + builder = func.builder + int_size = LLVMType.IntType(size) + ptr_casted = builder.inttoptr( + addr, + llvm_ir.PointerType(int_size) + ) + return builder.store(value, ptr_casted) + + +class LLVMFunction(object): + """Represent a LLVM function + + Implementation note: + A new module is created each time to avoid cumulative lag (if @new_module) + """ + + # Default logging values + log_mn = False + log_regs = True + + # Operation translation + ## Basics + op_translate = {'x86_cpuid': 'x86_cpuid', + } + ## Add the size as first argument + op_translate_with_size = {} + ## Add the size as suffix + op_translate_with_suffix_size = { + 'bcdadd': 'bcdadd', + 'bcdadd_cf': 'bcdadd_cf', + } + + def __init__(self, llvm_context, name="fc", new_module=True): + "Create a new function with name @name" + self.llvm_context = llvm_context + if new_module: + self.llvm_context.new_module() + self.mod = self.llvm_context.get_module() + + self.my_args = [] # (Expr, LLVMType, Name) + self.ret_type = None + self.builder = None + self.entry_bbl = None + + self.branch_counter = 0 + self.name = name + self._llvm_mod = None + + # Constructor utils + + def new_branch_name(self): + "Return a new branch name" + self.branch_counter += 1 + return str(self.branch_counter) + + def append_basic_block(self, label, overwrite=True): + """Add a new basic block to the current function. + @label: str or asmlabel + @overwrite: if False, do nothing if a bbl with the same name already exists + Return the corresponding LLVM Basic Block""" + name = self.llvm_context.canonize_label_name(label) + bbl = self.name2bbl.get(name, None) + if not overwrite and bbl is not None: + return bbl + bbl = self.fc.append_basic_block(name) + self.name2bbl[name] = bbl + + return bbl + + def CreateEntryBlockAlloca(self, var_type, default_value=None): + """Create an alloca instruction at the beginning of the current fc + @default_value: if set, store the default_value just after the allocation + """ + builder = self.builder + current_bbl = builder.basic_block + builder.position_at_start(self.entry_bbl) + + ret = builder.alloca(var_type) + if default_value is not None: + builder.store(default_value, ret) + builder.position_at_end(current_bbl) + return ret + + def get_ptr_by_expr(self, expr): + """"Return a pointer casted corresponding to ExprId expr. If it is not + already computed, compute it at the end of entry_bloc""" + + name = expr.name + + ptr_casted = self.local_vars_pointers.get(name, None) + if ptr_casted is not None: + # If the pointer has already been computed + return ptr_casted + + # Get current objects + builder = self.builder + current_bbl = builder.basic_block + + # Go at the right position + entry_bloc_bbl = self.entry_bbl + builder.position_at_end(entry_bloc_bbl) + + # Compute the pointer address + offset = self.llvm_context.vmcpu[name] + + # Pointer cast + ptr = builder.gep( + self.local_vars["vmcpu"], + [ + llvm_ir.Constant( + LLVMType.IntType(), + offset + ) + ] + ) + pointee_type = LLVMType.IntType(expr.size) + ptr_casted = builder.bitcast( + ptr, + llvm_ir.PointerType(pointee_type) + ) + # Store in cache + self.local_vars_pointers[name] = ptr_casted + + # Reset builder + builder.position_at_end(current_bbl) + + return ptr_casted + + def update_cache(self, name, value): + "Add 'name' = 'value' to the cache iff main_stream = True" + + if self.main_stream is True: + self.expr_cache[name] = value + + def set_ret(self, var): + "Cast @var and return it at the end of current bbl" + if var.type.width < 64: + var_casted = self.builder.zext(var, LLVMType.IntType(64)) + else: + var_casted = var + self.builder.ret(var_casted) + + def get_basic_block_by_loc_key(self, loc_key): + "Return the bbl corresponding to label, None otherwise" + return self.name2bbl.get( + self.llvm_context.canonize_label_name(loc_key), + None + ) + + def global_constant(self, name, value): + """ + Inspired from numba/cgutils.py + + Get or create a (LLVM module-)global constant with *name* or *value*. + """ + if name in self.mod.globals: + return self.mod.globals[name] + data = llvm_ir.GlobalVariable(self.mod, value.type, name=name) + data.global_constant = True + data.initializer = value + return data + + def make_bytearray(self, buf): + """ + Inspired from numba/cgutils.py + + Make a byte array constant from *buf*. + """ + b = bytearray(buf) + n = len(b) + return llvm_ir.Constant(llvm_ir.ArrayType(llvm_ir.IntType(8), n), b) + + def printf(self, format, *args): + """ + Inspired from numba/cgutils.py + + Calls printf(). + Argument `format` is expected to be a Python string. + Values to be printed are listed in `args`. + + Note: There is no checking to ensure there is correct number of values + in `args` and there type matches the declaration in the format string. + """ + assert isinstance(format, str) + mod = self.mod + # Make global constant for format string + cstring = llvm_ir.IntType(8).as_pointer() + fmt_bytes = self.make_bytearray((format + '\00').encode('ascii')) + + base_name = "printf_format" + count = 0 + while "%s_%d" % (base_name, count) in self.mod.globals: + count += 1 + global_fmt = self.global_constant( + "%s_%d" % (base_name, count), + fmt_bytes + ) + fnty = llvm_ir.FunctionType( + llvm_ir.IntType(32), + [cstring], + var_arg=True + ) + # Insert printf() + fn = mod.globals.get('printf', None) + if fn is None: + fn = llvm_ir.Function(mod, fnty, name="printf") + # Call + ptr_fmt = self.builder.bitcast(global_fmt, cstring) + return self.builder.call(fn, [ptr_fmt] + list(args)) + + # Effective constructors + + def assign(self, src, dst): + "Assign from LLVM src to M2 dst" + + # Destination + builder = self.builder + + if isinstance(dst, ExprId): + ptr_casted = self.get_ptr_by_expr(dst) + builder.store(src, ptr_casted) + + elif isinstance(dst, ExprMem): + addr = self.add_ir(dst.ptr) + self.llvm_context.memory_write(self, addr, dst.size, src) + else: + raise Exception("UnknownAssignmentType") + + def init_fc(self): + "Init the function" + + # Build type for fc signature + fc_type = llvm_ir.FunctionType( + self.ret_type, + [k[1] for k in self.my_args] + ) + + # Add fc in module + try: + fc = llvm_ir.Function(self.mod, fc_type, name=self.name) + except llvm.LLVMException: + # Overwrite the previous function + previous_fc = self.mod.get_global(self.name) + previous_fc.delete() + fc = self.mod.add_function(fc_type, self.name) + + # Name args + for i, a in enumerate(self.my_args): + fc.args[i].name = a[2] + + # Initialize local variable pool + self.local_vars = {} + self.local_vars_pointers = {} + for i, a in enumerate(self.my_args): + self.local_vars[a[2]] = fc.args[i] + + # Init cache + self.expr_cache = {} + self.main_stream = True + self.name2bbl = {} + + # Function link + self.fc = fc + + # Add a first BasicBlock + self.entry_bbl = self.append_basic_block("entry") + + # Instruction builder + self.builder = llvm_ir.IRBuilder(self.entry_bbl) + + def add_ir(self, expr): + "Add a Miasm2 IR to the last bbl. Return the var created" + + if self.main_stream is True and expr in self.expr_cache: + return self.expr_cache[expr] + + builder = self.builder + + if isinstance(expr, ExprInt): + ret = llvm_ir.Constant(LLVMType.IntType(expr.size), int(expr)) + self.update_cache(expr, ret) + return ret + + if expr.is_loc(): + offset = self.llvm_context.lifter.loc_db.get_location_offset( + expr.loc_key + ) + ret = llvm_ir.Constant(LLVMType.IntType(expr.size), offset) + self.update_cache(expr, ret) + return ret + + if isinstance(expr, ExprId): + name = expr.name + try: + # If expr.name is already known (args) + return self.local_vars[name] + except KeyError: + pass + + ptr_casted = self.get_ptr_by_expr(expr) + + var = builder.load(ptr_casted, name) + self.update_cache(expr, var) + return var + + if isinstance(expr, ExprOp): + op = expr.op + + if (op in self.op_translate or + op in self.op_translate_with_size or + op in self.op_translate_with_suffix_size): + args = [self.add_ir(arg) for arg in expr.args] + arg_size = expr.args[0].size + + if op in self.op_translate_with_size: + fc_name = self.op_translate_with_size[op] + arg_size_cst = llvm_ir.Constant(LLVMType.IntType(64), + arg_size) + args = [arg_size_cst] + args + elif op in self.op_translate: + fc_name = self.op_translate[op] + elif op in self.op_translate_with_suffix_size: + fc_name = "%s_%s" % (self.op_translate[op], arg_size) + + fc_ptr = self.mod.get_global(fc_name) + + # Cast args if needed + casted_args = [] + for i, arg in enumerate(args): + if arg.type.width < fc_ptr.args[i].type.width: + casted_args.append( + builder.zext( + arg, + fc_ptr.args[i].type + ) + ) + else: + casted_args.append(arg) + ret = builder.call(fc_ptr, casted_args) + + # Cast ret if needed + ret_size = fc_ptr.return_value.type.width + if ret_size > expr.size: + ret = builder.trunc(ret, LLVMType.IntType(expr.size)) + + self.update_cache(expr, ret) + return ret + + if op == "-": + # Unsupported op '-' with more than 1 arg + assert len(expr.args) == 1 + zero = LLVMType.IntType(expr.size)(0) + ret = builder.sub(zero, self.add_ir(expr.args[0])) + self.update_cache(expr, ret) + return ret + + if op == "parity": + assert len(expr.args) == 1 + arg = self.add_ir(expr.args[0]) + truncated = builder.trunc(arg, LLVMType.IntType(8)) + bitcount = builder.call( + self.mod.get_global("llvm.ctpop.i8"), + [truncated] + ) + ret = builder.not_(builder.trunc(bitcount, LLVMType.IntType(1))) + self.update_cache(expr, ret) + return ret + + if op in ["cntleadzeros", "cnttrailzeros"]: + assert len(expr.args) == 1 + arg = self.add_ir(expr.args[0]) + func_name = { + "cntleadzeros": "ctlz", + "cnttrailzeros": "cttz", + }[op] + func_llvm_name = "llvm.%s.i%d" % (func_name, expr.size) + func_sig = { + func_llvm_name: { + "ret": LLVMType.IntType(expr.size), + "args": [LLVMType.IntType(expr.args[0].size)] + } + } + try: + self.mod.get_global(func_llvm_name) + except KeyError: + self.llvm_context.add_fc(func_sig, readonly=True) + ret = builder.call( + self.mod.get_global(func_llvm_name), + [arg] + ) + self.update_cache(expr, ret) + return ret + + + if op.startswith('zeroExt_'): + arg = expr.args[0] + if expr.size == arg.size: + return arg + new_expr = ExprCompose(arg, ExprInt(0, expr.size - arg.size)) + return self.add_ir(new_expr) + + if op.startswith("signExt_"): + arg = expr.args[0] + add_size = expr.size - arg.size + new_expr = ExprCompose( + arg, + ExprCond( + arg.msb(), + ExprInt(size2mask(add_size), add_size), + ExprInt(0, add_size) + ) + ) + return self.add_ir(new_expr) + + + if op == "segm": + fc_ptr = self.mod.get_global("segm2addr") + + # Cast args if needed + args = [self.add_ir(arg) for arg in expr.args] + casted_args = [] + for i, arg in enumerate(args, 1): + if arg.type.width < fc_ptr.args[i].type.width: + casted_args.append( + builder.zext( + arg, + fc_ptr.args[i].type + ) + ) + else: + casted_args.append(arg) + + ret = builder.call( + fc_ptr, + [self.local_vars["jitcpu"]] + casted_args + ) + if ret.type.width > expr.size: + ret = builder.trunc(ret, LLVMType.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op in ["smod", "sdiv", "umod", "udiv"]: + assert len(expr.args) == 2 + + arg_b = self.add_ir(expr.args[1]) + arg_a = self.add_ir(expr.args[0]) + + if op == "smod": + callback = builder.srem + elif op == "sdiv": + callback = builder.sdiv + elif op == "umod": + callback = builder.urem + elif op == "udiv": + callback = builder.udiv + + ret = callback(arg_a, arg_b) + self.update_cache(expr, ret) + return ret + + unsigned_cmps = { + "==": "==", + "<u": "<", + "<=u": "<=" + } + if op in unsigned_cmps: + op = unsigned_cmps[op] + args = [self.add_ir(arg) for arg in expr.args] + ret = builder.select( + builder.icmp_unsigned(op, + args[0], + args[1] + ), + llvm_ir.IntType(expr.size)(1), + llvm_ir.IntType(expr.size)(0) + ) + self.update_cache(expr, ret) + return ret + + if op in [">>", "<<", "a>>"]: + assert len(expr.args) == 2 + # Undefined behavior must be enforced to 0 + count = self.add_ir(expr.args[1]) + value = self.add_ir(expr.args[0]) + itype = LLVMType.IntType(expr.size) + cond_ok = self.builder.icmp_unsigned( + "<", + count, + itype(expr.size) + ) + zero = itype(0) + if op == ">>": + callback = builder.lshr + elif op == "<<": + callback = builder.shl + elif op == "a>>": + callback = builder.ashr + # x a>> size is 0 or -1, depending on x sign + cond_neg = self.builder.icmp_signed("<", value, zero) + zero = self.builder.select(cond_neg, itype(-1), zero) + + ret = self.builder.select( + cond_ok, + callback(value, count), + zero + ) + self.update_cache(expr, ret) + return ret + + + if op in ['<<<', '>>>']: + assert len(expr.args) == 2 + # First compute rotation modulus size + count = self.add_ir(expr.args[1]) + value = self.add_ir(expr.args[0]) + itype = LLVMType.IntType(expr.size) + expr_size = itype(expr.size) + + # As shift of expr_size is undefined, we urem the shifters + shift = builder.urem(count, expr_size) + shift_inv = builder.urem( + builder.sub(expr_size, shift), + expr_size + ) + + if op == '<<<': + part_a = builder.shl(value, shift) + part_b = builder.lshr(value, shift_inv) + else: + part_a = builder.lshr(value, shift) + part_b = builder.shl(value, shift_inv) + ret = builder.or_(part_a, part_b) + self.update_cache(expr, ret) + return ret + + if op == "sint_to_fp": + fptype = LLVMType.fptype(expr.size) + arg = self.add_ir(expr.args[0]) + ret = builder.sitofp(arg, fptype) + ret = builder.bitcast(ret, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op.startswith("fp_to_sint"): + size_arg = expr.args[0].size + fptype_orig = LLVMType.fptype(size_arg) + arg = self.add_ir(expr.args[0]) + arg = builder.bitcast(arg, fptype_orig) + # Enforce IEEE-754 behavior. This could be enhanced with + # 'llvm.experimental.constrained.nearbyint' + if size_arg == 32: + func = self.mod.get_global("llvm.nearbyint.f32") + elif size_arg == 64: + func = self.mod.get_global("llvm.nearbyint.f64") + else: + raise RuntimeError("Unsupported size") + rounded = builder.call(func, [arg]) + ret = builder.fptoui(rounded, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op.startswith("fpconvert_fp"): + assert len(expr.args) == 1 + size_arg = expr.args[0].size + fptype = LLVMType.fptype(expr.size) + fptype_orig = LLVMType.fptype(size_arg) + arg = self.add_ir(expr.args[0]) + arg = builder.bitcast(arg, fptype_orig) + if expr.size > size_arg: + fc = builder.fpext + elif expr.size < size_arg: + fc = builder.fptrunc + else: + raise RuntimeError("Not supported, same size") + ret = fc(arg, fptype) + ret = builder.bitcast(ret, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op.startswith("fpround_"): + assert len(expr.args) == 1 + fptype = LLVMType.fptype(expr.size) + arg = self.add_ir(expr.args[0]) + arg = builder.bitcast(arg, fptype) + if op == "fpround_towardszero" and expr.size == 32: + fc = self.mod.get_global("llvm.trunc.f32") + else: + raise RuntimeError("Not supported, same size") + rounded = builder.call(fc, [arg]) + ret = builder.bitcast(rounded, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op in ["fcom_c0", "fcom_c1", "fcom_c2", "fcom_c3"]: + arg1 = self.add_ir(expr.args[0]) + arg2 = self.add_ir(expr.args[0]) + fc_name = "fpu_%s" % op + fc_ptr = self.mod.get_global(fc_name) + casted_args = [ + builder.bitcast(arg1, llvm_ir.DoubleType()), + builder.bitcast(arg2, llvm_ir.DoubleType()), + ] + ret = builder.call(fc_ptr, casted_args) + + # Cast ret if needed + ret_size = fc_ptr.return_value.type.width + if ret_size > expr.size: + ret = builder.trunc(ret, LLVMType.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op in ["fsqrt", "fabs"]: + arg = self.add_ir(expr.args[0]) + if op == "fsqrt": + op = "sqrt" + + # Apply the correct func + if expr.size == 32: + arg = builder.bitcast(arg, llvm_ir.FloatType()) + ret = builder.call( + self.mod.get_global("llvm.%s.f32" % op), + [arg] + ) + elif expr.size == 64: + arg = builder.bitcast(arg, llvm_ir.DoubleType()) + ret = builder.call( + self.mod.get_global("llvm.%s.f64" % op), + [arg] + ) + else: + raise RuntimeError("Unsupported precision: %x", expr.size) + + ret = builder.bitcast(ret, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op in ["fadd", "fmul", "fsub", "fdiv"]: + # More than 2 args not yet supported + assert len(expr.args) == 2 + arg1 = self.add_ir(expr.args[0]) + arg2 = self.add_ir(expr.args[1]) + precision = LLVMType.fptype(expr.size) + arg1 = builder.bitcast(arg1, precision) + arg2 = builder.bitcast(arg2, precision) + if op == "fadd": + ret = builder.fadd(arg1, arg2) + elif op == "fmul": + ret = builder.fmul(arg1, arg2) + elif op == "fsub": + ret = builder.fsub(arg1, arg2) + elif op == "fdiv": + ret = builder.fdiv(arg1, arg2) + ret = builder.bitcast(ret, llvm_ir.IntType(expr.size)) + self.update_cache(expr, ret) + return ret + + if op in [ + TOK_EQUAL, + TOK_INF_SIGNED, + TOK_INF_EQUAL_SIGNED, + TOK_INF_UNSIGNED, + TOK_INF_EQUAL_UNSIGNED, + ]: + if op == TOK_EQUAL: + opname = "==" + callback = builder.icmp_unsigned + elif op == TOK_INF_SIGNED: + opname = "<" + callback = builder.icmp_signed + elif op == TOK_INF_UNSIGNED: + opname = "<" + callback = builder.icmp_unsigned + elif op == TOK_INF_EQUAL_SIGNED: + opname = "<=" + callback = builder.icmp_signed + elif op == TOK_INF_EQUAL_UNSIGNED: + opname = "<" + callback = builder.icmp_unsigned + + left = self.add_ir(expr.args[0]) + right = self.add_ir(expr.args[1]) + + ret = callback(opname, left, right) + self.update_cache(expr, ret) + + return ret + + if len(expr.args) > 1: + + if op == "*": + callback = builder.mul + elif op == "+": + callback = builder.add + elif op == "&": + callback = builder.and_ + elif op == "^": + callback = builder.xor + elif op == "|": + callback = builder.or_ + elif op == "%": + callback = builder.urem + elif op == "/": + callback = builder.udiv + else: + raise NotImplementedError('Unknown op: %s' % op) + + last = self.add_ir(expr.args[0]) + + for i in range(1, len(expr.args)): + last = callback(last, + self.add_ir(expr.args[i])) + + self.update_cache(expr, last) + + return last + + raise NotImplementedError() + + if isinstance(expr, ExprMem): + + addr = self.add_ir(expr.ptr) + ret = self.llvm_context.memory_lookup(self, addr, expr.size) + self.update_cache(expr, ret) + return ret + + if isinstance(expr, ExprCond): + # Compute cond + cond = self.add_ir(expr.cond) + zero_casted = LLVMType.IntType(expr.cond.size)(0) + condition_bool = builder.icmp_unsigned("!=", cond, + zero_casted) + then_value = self.add_ir(expr.src1) + else_value = self.add_ir(expr.src2) + ret = builder.select(condition_bool, then_value, else_value) + + self.update_cache(expr, ret) + return ret + + if isinstance(expr, ExprSlice): + + src = self.add_ir(expr.arg) + + # Remove trailing bits + if expr.start != 0: + to_shr = llvm_ir.Constant( + LLVMType.IntType(expr.arg.size), + expr.start + ) + shred = builder.lshr(src, to_shr) + else: + shred = src + + # Remove leading bits + to_and = llvm_ir.Constant( + LLVMType.IntType(expr.arg.size), + (1 << (expr.stop - expr.start)) - 1 + ) + anded = builder.and_(shred, + to_and) + + # Cast into e.size + ret = builder.trunc( + anded, + LLVMType.IntType(expr.size) + ) + + self.update_cache(expr, ret) + return ret + + if isinstance(expr, ExprCompose): + + args = [] + + # Build each part + for start, src in expr.iter_args(): + # src & size + src = self.add_ir(src) + src_casted = builder.zext( + src, + LLVMType.IntType(expr.size) + ) + to_and = llvm_ir.Constant( + LLVMType.IntType(expr.size), + (1 << src.type.width) - 1 + ) + anded = builder.and_(src_casted, + to_and) + + if (start != 0): + # result << start + to_shl = llvm_ir.Constant( + LLVMType.IntType(expr.size), + start + ) + shled = builder.shl(anded, to_shl) + final = shled + else: + # Optimisation + final = anded + + args.append(final) + + # result = part1 | part2 | ... + last = args[0] + for i in range(1, len(expr.args)): + last = builder.or_(last, args[i]) + + self.update_cache(expr, last) + return last + + raise Exception("UnkownExpression", expr.__class__.__name__) + + # JiT specifics + + def check_memory_exception(self, offset, restricted_exception=False): + """Add a check for memory errors. + @offset: offset of the current exception (int or Instruction) + If restricted_exception, check only for exception which do not + require a pc update, and do not consider automod exception""" + + # VmMngr "get_exception_flag" return's size + size = 64 + t_size = LLVMType.IntType(size) + + # Get exception flag value + # TODO: avoid costly call using a structure deref + builder = self.builder + fc_ptr = self.mod.get_global("get_exception_flag") + exceptionflag = builder.call(fc_ptr, [self.local_vars["vmmngr"]]) + + if restricted_exception is True: + flag = ~m2_csts.EXCEPT_CODE_AUTOMOD & m2_csts.EXCEPT_DO_NOT_UPDATE_PC + m2_flag = llvm_ir.Constant(t_size, flag) + exceptionflag = builder.and_(exceptionflag, m2_flag) + + # Compute cond + zero_casted = llvm_ir.Constant(t_size, 0) + condition_bool = builder.icmp_unsigned( + "!=", + exceptionflag, + zero_casted + ) + + # Create bbls + branch_id = self.new_branch_name() + then_block = self.append_basic_block('then%s' % branch_id) + merge_block = self.append_basic_block('ifcond%s' % branch_id) + + builder.cbranch(condition_bool, then_block, merge_block) + + # Deactivate object caching + current_main_stream = self.main_stream + self.main_stream = False + + # Then Block + builder.position_at_end(then_block) + PC = self.llvm_context.PC + if isinstance(offset, int_types): + offset = self.add_ir(ExprInt(offset, PC.size)) + self.assign(offset, PC) + self.assign(self.add_ir(ExprInt(1, 8)), ExprId("status", 32)) + self.set_ret(offset) + + builder.position_at_end(merge_block) + # Reactivate object caching + self.main_stream = current_main_stream + + def check_cpu_exception(self, offset, restricted_exception=False): + """Add a check for CPU errors. + @offset: offset of the current exception (int or Instruction) + If restricted_exception, check only for exception which do not + require a pc update""" + + # Get exception flag value + builder = self.builder + m2_exception_flag = self.llvm_context.lifter.arch.regs.exception_flags + t_size = LLVMType.IntType(m2_exception_flag.size) + exceptionflag = self.add_ir(m2_exception_flag) + + # Compute cond + if restricted_exception is True: + flag = m2_csts.EXCEPT_NUM_UPDT_EIP + condition_bool = builder.icmp_unsigned( + ">", + exceptionflag, + llvm_ir.Constant(t_size, flag) + ) + else: + zero_casted = llvm_ir.Constant(t_size, 0) + condition_bool = builder.icmp_unsigned( + "!=", + exceptionflag, + zero_casted + ) + + # Create bbls + branch_id = self.new_branch_name() + then_block = self.append_basic_block('then%s' % branch_id) + merge_block = self.append_basic_block('ifcond%s' % branch_id) + + builder.cbranch(condition_bool, then_block, merge_block) + + # Deactivate object caching + current_main_stream = self.main_stream + self.main_stream = False + + # Then Block + builder.position_at_end(then_block) + PC = self.llvm_context.PC + if isinstance(offset, int_types): + offset = self.add_ir(ExprInt(offset, PC.size)) + self.assign(offset, PC) + self.assign(self.add_ir(ExprInt(1, 8)), ExprId("status", 32)) + self.set_ret(offset) + + builder.position_at_end(merge_block) + # Reactivate object caching + self.main_stream = current_main_stream + + def gen_pre_code(self, instr_attrib): + if instr_attrib.log_mn: + loc_db = self.llvm_context.lifter.loc_db + self.printf( + "%.8X %s\n" % ( + instr_attrib.instr.offset, + instr_attrib.instr.to_string(loc_db) + ) + ) + + def gen_post_code(self, attributes, pc_value): + if attributes.log_regs: + # Update PC for dump_gpregs + PC = self.llvm_context.PC + t_size = LLVMType.IntType(PC.size) + dst = self.builder.zext(t_size(pc_value), t_size) + self.assign(dst, PC) + + fc_ptr = self.mod.get_global(self.llvm_context.logging_func) + self.builder.call(fc_ptr, [self.local_vars["vmcpu"]]) + + def gen_post_instr_checks(self, attrib, next_instr): + if attrib.mem_read | attrib.mem_write: + fc_ptr = self.mod.get_global("check_memory_breakpoint") + self.builder.call(fc_ptr, [self.local_vars["vmmngr"]]) + fc_ptr = self.mod.get_global("check_invalid_code_blocs") + self.builder.call(fc_ptr, [self.local_vars["vmmngr"]]) + self.check_memory_exception(next_instr, restricted_exception=False) + + if attrib.set_exception: + self.check_cpu_exception(next_instr, restricted_exception=False) + + if attrib.mem_read | attrib.mem_write: + fc_ptr = self.mod.get_global("reset_memory_access") + self.builder.call(fc_ptr, [self.local_vars["vmmngr"]]) + + def expr2cases(self, expr): + """ + Evaluate @expr and return: + - switch value -> dst + - evaluation of the switch value (if any) + """ + + to_eval = expr + dst2case = {} + case2dst = {} + for i, solution in enumerate(possible_values(expr)): + value = solution.value + index = dst2case.get(value, i) + to_eval = to_eval.replace_expr({value: ExprInt(index, value.size)}) + dst2case[value] = index + if value.is_int() or value.is_loc(): + case2dst[i] = value + else: + case2dst[i] = self.add_ir(value) + + + evaluated = self.add_ir(to_eval) + return case2dst, evaluated + + def gen_jump2dst(self, attrib, instr_offsets, dst): + """Generate the code for a jump to @dst with final check for error + + Several cases have to be considered: + - jump to an offset out of the current ASM BBL (JMP 0x11223344) + - jump to an offset inside the current ASM BBL (Go to next instruction) + - jump to an offset back in the current ASM BBL (For max_exec jit + option on self loops) + - jump to a generated IR label, which must be jitted in this same + function (REP MOVSB) + - jump to a computed offset (CALL @32[0x11223344]) + + """ + PC = self.llvm_context.PC + # We are no longer in the main stream, deactivate cache + self.main_stream = False + + offset = None + if isinstance(dst, ExprInt): + offset = int(dst) + loc_key = self.llvm_context.lifter.loc_db.get_or_create_offset_location(offset) + dst = ExprLoc(loc_key, dst.size) + + if isinstance(dst, ExprLoc): + loc_key = dst.loc_key + bbl = self.get_basic_block_by_loc_key(loc_key) + offset = self.llvm_context.lifter.loc_db.get_location_offset(loc_key) + if bbl is not None: + # "local" jump, inside this function + if offset is None: + # Avoid checks on generated label + self.builder.branch(bbl) + return + + if (offset in instr_offsets and + offset > attrib.instr.offset): + # forward local jump (ie. next instruction) + self.gen_post_code(attrib, offset) + self.gen_post_instr_checks(attrib, offset) + self.builder.branch(bbl) + return + + # reaching this point means a backward local jump, promote it to + # extern + + # "extern" jump on a defined offset, return to the caller + dst = self.add_ir(ExprInt(offset, PC.size)) + + # "extern" jump with a computed value, return to the caller + assert isinstance(dst, (llvm_ir.Instruction, llvm_ir.Value)) + # Cast @dst, if needed + # for instance, x86_32: IRDst is 32 bits, so is @dst; PC is 64 bits + if dst.type.width != PC.size: + dst = self.builder.zext(dst, LLVMType.IntType(PC.size)) + + self.gen_post_code(attrib, offset) + self.assign(dst, PC) + self.gen_post_instr_checks(attrib, dst) + self.assign(self.add_ir(ExprInt(0, 8)), ExprId("status", 32)) + self.set_ret(dst) + + + def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock): + """ + Generate the code for an @irblock + @instr_attrib: an Attributes instance or the instruction to translate + @attributes: list of Attributes corresponding to irblock assignments + @instr_offsets: offset of all asmblock's instructions + @irblock: an irblock instance + """ + + case2dst = None + case_value = None + instr = instr_attrib.instr + + for index, assignblk in enumerate(irblock): + # Enable cache + self.main_stream = True + self.expr_cache = {} + + # Prefetch memory + for element in assignblk.get_r(mem_read=True): + if isinstance(element, ExprMem): + self.add_ir(element) + + # Evaluate expressions + values = {} + for dst, src in viewitems(assignblk): + if dst == self.llvm_context.lifter.IRDst: + case2dst, case_value = self.expr2cases(src) + else: + values[dst] = self.add_ir(src) + + # Check memory access exception + if attributes[index].mem_read: + self.check_memory_exception( + instr.offset, + restricted_exception=True + ) + + # Update the memory + for dst, src in viewitems(values): + if isinstance(dst, ExprMem): + self.assign(src, dst) + + # Check memory write exception + if attributes[index].mem_write: + self.check_memory_exception( + instr.offset, + restricted_exception=True + ) + + # Update registers values + for dst, src in viewitems(values): + if not isinstance(dst, ExprMem): + self.assign(src, dst) + + # Check post assignblk exception flags + if attributes[index].set_exception: + self.check_cpu_exception( + instr.offset, + restricted_exception=True + ) + + # Destination + assert case2dst is not None + if len(case2dst) == 1: + # Avoid switch in this common case + self.gen_jump2dst( + instr_attrib, + instr_offsets, + next(iter(viewvalues(case2dst))) + ) + else: + current_bbl = self.builder.basic_block + + # Gen the out cases + branch_id = self.new_branch_name() + case2bbl = {} + for case, dst in list(viewitems(case2dst)): + name = "switch_%s_%d" % (branch_id, case) + bbl = self.append_basic_block(name) + case2bbl[case] = bbl + self.builder.position_at_start(bbl) + self.gen_jump2dst(instr_attrib, instr_offsets, dst) + + # Jump on the correct output + self.builder.position_at_end(current_bbl) + switch = self.builder.switch(case_value, case2bbl[0]) + for i, bbl in viewitems(case2bbl): + if i == 0: + # Default case is case 0, arbitrary + continue + switch.add_case(i, bbl) + + def gen_bad_block(self, asmblock): + """ + Translate an asm_bad_block into a CPU exception + """ + builder = self.builder + m2_exception_flag = self.llvm_context.lifter.arch.regs.exception_flags + t_size = LLVMType.IntType(m2_exception_flag.size) + self.assign( + self.add_ir(ExprInt(1, 8)), + ExprId("status", 32) + ) + self.assign( + t_size(m2_csts.EXCEPT_UNK_MNEMO), + m2_exception_flag + ) + offset = self.llvm_context.lifter.loc_db.get_location_offset( + asmblock.loc_key + ) + self.set_ret(LLVMType.IntType(64)(offset)) + + def gen_finalize(self, asmblock, codegen): + """ + In case of delayslot, generate a dummy BBL which return on the computed + IRDst or on next_label + """ + if self.llvm_context.has_delayslot: + next_label = codegen.get_block_post_label(asmblock) + builder = self.builder + + builder.position_at_end(self.get_basic_block_by_loc_key(next_label)) + + # Common code + self.assign(self.add_ir(ExprInt(0, 8)), + ExprId("status", 32)) + + # Check if IRDst has been set + zero_casted = LLVMType.IntType(codegen.delay_slot_set.size)(0) + condition_bool = builder.icmp_unsigned( + "!=", + self.add_ir(codegen.delay_slot_set), + zero_casted + ) + + # Create bbls + branch_id = self.new_branch_name() + then_block = self.append_basic_block('then%s' % branch_id) + else_block = self.append_basic_block('else%s' % branch_id) + + builder.cbranch(condition_bool, then_block, else_block) + + # Deactivate object caching + self.main_stream = False + + # Then Block + builder.position_at_end(then_block) + PC = self.llvm_context.PC + to_ret = self.add_ir(codegen.delay_slot_dst) + self.assign(to_ret, PC) + self.assign(self.add_ir(ExprInt(0, 8)), + ExprId("status", 32)) + self.set_ret(to_ret) + + # Else Block + builder.position_at_end(else_block) + PC = self.llvm_context.PC + next_label_offset = self.llvm_context.lifter.loc_db.get_location_offset(next_label) + to_ret = LLVMType.IntType(PC.size)(next_label_offset) + self.assign(to_ret, PC) + self.set_ret(to_ret) + + def from_asmblock(self, asmblock): + """Build the function from an asmblock (asm_block instance). + Prototype : f(i8* jitcpu, i8* vmcpu, i8* vmmngr, i8* status)""" + + # Build function signature + self.my_args.append((ExprId("jitcpu", 32), + llvm_ir.PointerType(LLVMType.IntType(8)), + "jitcpu")) + self.my_args.append((ExprId("vmcpu", 32), + llvm_ir.PointerType(LLVMType.IntType(8)), + "vmcpu")) + self.my_args.append((ExprId("vmmngr", 32), + llvm_ir.PointerType(LLVMType.IntType(8)), + "vmmngr")) + self.my_args.append((ExprId("status", 32), + llvm_ir.PointerType(LLVMType.IntType(8)), + "status")) + ret_size = 64 + + self.ret_type = LLVMType.IntType(ret_size) + + # Initialise the function + self.init_fc() + self.local_vars_pointers["status"] = self.local_vars["status"] + + if isinstance(asmblock, m2_asmblock.AsmBlockBad): + self.gen_bad_block(asmblock) + return + + # Create basic blocks (for label branches) + entry_bbl, builder = self.entry_bbl, self.builder + for instr in asmblock.lines: + lbl = self.llvm_context.lifter.loc_db.get_or_create_offset_location(instr.offset) + self.append_basic_block(lbl) + + # TODO: merge duplicate code with CGen + codegen = self.llvm_context.cgen_class(self.llvm_context.lifter) + irblocks_list = codegen.block2assignblks(asmblock) + instr_offsets = [line.offset for line in asmblock.lines] + + # Prepare for delayslot + if self.llvm_context.has_delayslot: + for element in (codegen.delay_slot_dst, codegen.delay_slot_set): + eltype = LLVMType.IntType(element.size) + ptr = self.CreateEntryBlockAlloca( + eltype, + default_value=eltype(0) + ) + self.local_vars_pointers[element.name] = ptr + loc_key = codegen.get_block_post_label(asmblock) + offset = self.llvm_context.lifter.loc_db.get_location_offset(loc_key) + instr_offsets.append(offset) + self.append_basic_block(loc_key) + + # Add content + builder.position_at_end(entry_bbl) + + + for instr, irblocks in zip(asmblock.lines, irblocks_list): + instr_attrib, irblocks_attributes = codegen.get_attributes( + instr, + irblocks, + self.log_mn, + self.log_regs + ) + + # Pre-create basic blocks + for irblock in irblocks: + self.append_basic_block(irblock.loc_key, overwrite=False) + + # Generate the corresponding code + for index, irblock in enumerate(irblocks): + new_irblock = self.llvm_context.lifter.irbloc_fix_regs_for_mode( + irblock, self.llvm_context.lifter.attrib) + + # Set the builder at the beginning of the correct bbl + self.builder.position_at_end(self.get_basic_block_by_loc_key(new_irblock.loc_key)) + + if index == 0: + self.gen_pre_code(instr_attrib) + self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, new_irblock) + + # Gen finalize (see codegen::CGen) is unrecheable, except with delayslot + self.gen_finalize(asmblock, codegen) + + # Branch entry_bbl on first label + builder.position_at_end(entry_bbl) + first_label_bbl = self.get_basic_block_by_loc_key(asmblock.loc_key) + builder.branch(first_label_bbl) + + + # LLVMFunction manipulation + + def __str__(self): + "Print the llvm IR corresponding to the current module" + return str(self.mod) + + def dot(self): + "Return the CFG of the current function" + return llvm.get_function_cfg(self.fc) + + def as_llvm_mod(self): + """Return a ModuleRef standing for the current function""" + if self._llvm_mod is None: + self._llvm_mod = llvm.parse_assembly(str(self.mod)) + return self._llvm_mod + + def verify(self): + "Verify the module syntax" + return self.as_llvm_mod().verify() + + def get_bytecode(self): + "Return LLVM bitcode corresponding to the current module" + return self.as_llvm_mod().as_bitcode() + + def get_assembly(self): + "Return native assembly corresponding to the current module" + return self.llvm_context.target_machine.emit_assembly(self.as_llvm_mod()) + + def optimise(self): + "Optimise the function in place" + return self.llvm_context.pass_manager.run(self.as_llvm_mod()) + + def __call__(self, *args): + "Eval the function with arguments args" + + e = self.llvm_context.get_execengine() + + genargs = [LLVMType.generic(a) for a in args] + ret = e.run_function(self.fc, genargs) + + return ret.as_int() + + def get_function_pointer(self): + "Return a pointer on the Jitted function" + engine = self.llvm_context.get_execengine() + + # Add the module and make sure it is ready for execution + engine.add_module(self.as_llvm_mod()) + engine.finalize_object() + + return engine.get_function_address(self.fc.name) + + +class LLVMFunction_IRCompilation(LLVMFunction): + """LLVMFunction made for IR export, in conjunction with + LLVMContext_IRCompilation. + + This class offers only the basics, and decision must be made by the class + user on how actual registers, ABI, etc. are reflected + + + Example of use: + >>> context = LLVMContext_IRCompilation() + >>> context.lifter = lifter + >>> + >>> func = LLVMFunction_IRCompilation(context, name="test") + >>> func.ret_type = llvm_ir.VoidType() + >>> func.init_fc() + >>> + >>> # Insert here function additional inits + >>> XX = func.builder.alloca(...) + >>> func.local_vars_pointers["EAX"] = XX + >>> # + >>> + >>> func.from_ircfg(ircfg) + """ + + def init_fc(self): + super(LLVMFunction_IRCompilation, self).init_fc() + + # Create a global IRDst if not any + IRDst = self.llvm_context.lifter.IRDst + if str(IRDst) not in self.mod.globals: + llvm_ir.GlobalVariable(self.mod, LLVMType.IntType(IRDst.size), + name=str(IRDst)) + + # Create an 'exit' basic block, the final leave + self.exit_bbl = self.append_basic_block("exit") + + def gen_jump2dst(self, _attrib, _instr_offsets, dst): + self.main_stream = False + + if isinstance(dst, Expr): + if dst.is_int(): + loc = self.llvm_context.lifter.loc_db.getby_offset_create(int(dst)) + dst = ExprLoc(loc, dst.size) + assert dst.is_loc() + bbl = self.get_basic_block_by_loc_key(dst.loc_key) + if bbl is not None: + # "local" jump, inside this function + self.builder.branch(bbl) + return + + # extern jump + dst = self.add_ir(dst) + + # Emulate indirect jump with: + # @IRDst = dst + # goto exit + self.builder.store(dst, self.mod.get_global("IRDst")) + self.builder.branch(self.exit_bbl) + + def gen_irblock(self, irblock): + instr_attrib = Attributes() + attributes = [Attributes() for _ in range(len(irblock.assignblks))] + instr_offsets = None + return super(LLVMFunction_IRCompilation, self).gen_irblock( + instr_attrib, attributes, instr_offsets, irblock + ) + + def from_ircfg(self, ircfg, append_ret=True): + # Create basic blocks + for loc_key, irblock in viewitems(ircfg.blocks): + self.append_basic_block(loc_key) + + # Add IRBlocks + for label, irblock in viewitems(ircfg.blocks): + self.builder.position_at_end(self.get_basic_block_by_loc_key(label)) + self.gen_irblock(irblock) + + # Branch the entry BBL on the IRCFG head + self.builder.position_at_end(self.entry_bbl) + heads = ircfg.heads() + assert len(heads) == 1 + starting_label = list(heads).pop() + self.builder.branch(self.get_basic_block_by_loc_key(starting_label)) + + # Returns with the builder on the exit block + self.builder.position_at_end(self.exit_bbl) + + if append_ret: + self.builder.ret_void() diff --git a/src/miasm/jitter/loader/__init__.py b/src/miasm/jitter/loader/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/miasm/jitter/loader/__init__.py diff --git a/src/miasm/jitter/loader/elf.py b/src/miasm/jitter/loader/elf.py new file mode 100644 index 00000000..91d1c18b --- /dev/null +++ b/src/miasm/jitter/loader/elf.py @@ -0,0 +1,339 @@ +import struct +from collections import defaultdict + +from future.utils import viewitems + +from miasm.loader import cstruct +from miasm.loader import * +import miasm.loader.elf as elf_csts + +from miasm.jitter.csts import * +from miasm.jitter.loader.utils import canon_libname_libfunc, libimp +from miasm.core.utils import force_str +from miasm.core.interval import interval + +import logging + +log = logging.getLogger('loader_elf') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.CRITICAL) + + +def get_import_address_elf(e): + import2addr = defaultdict(set) + for sh in e.sh: + if not hasattr(sh, 'rel'): + continue + for k, v in viewitems(sh.rel): + k = force_str(k) + import2addr[('xxx', k)].add(v.offset) + return import2addr + + +def preload_elf(vm, e, runtime_lib, patch_vm_imp=True, loc_db=None): + # XXX quick hack + fa = get_import_address_elf(e) + dyn_funcs = {} + for (libname, libfunc), ads in viewitems(fa): + # Quick hack - if a symbol is already known, do not stub it + if loc_db and loc_db.get_name_location(libfunc) is not None: + continue + for ad in ads: + ad_base_lib = runtime_lib.lib_get_add_base(libname) + ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad) + + libname_s = canon_libname_libfunc(libname, libfunc) + dyn_funcs[libname_s] = ad_libfunc + if patch_vm_imp: + log.debug('patch 0x%x 0x%x %s', ad, ad_libfunc, libfunc) + set_endianness = { elf_csts.ELFDATA2MSB: ">", + elf_csts.ELFDATA2LSB: "<", + elf_csts.ELFDATANONE: "" }[e.sex] + vm.set_mem(ad, + struct.pack(set_endianness + + cstruct.size2type[e.size], + ad_libfunc)) + return runtime_lib, dyn_funcs + +def fill_loc_db_with_symbols(elf, loc_db, base_addr=0): + """Parse the miasm.loader's ELF @elf to extract symbols, and fill the LocationDB + instance @loc_db with parsed symbols. + + The ELF is considered mapped at @base_addr + @elf: miasm.loader's ELF instance + @loc_db: LocationDB used to retrieve symbols'offset + @base_addr: addr to reloc to (if any) + """ + # Get symbol sections + symbol_sections = [] + for section_header in elf.sh: + if hasattr(section_header, 'symbols'): + for name, sym in viewitems(section_header.symbols): + if not name or sym.value == 0: + continue + name = loc_db.find_free_name(force_str(name)) + loc_db.add_location(name, sym.value, strict=False) + + if hasattr(section_header, 'reltab'): + for rel in section_header.reltab: + if not rel.sym or rel.offset == 0: + continue + name = loc_db.find_free_name(force_str(rel.sym)) + loc_db.add_location(name, rel.offset, strict=False) + + if hasattr(section_header, 'symtab'): + log.debug("Find %d symbols in %r", len(section_header.symtab), + section_header) + symbol_sections.append(section_header) + elif isinstance(section_header, ( + elf_init.GNUVerDef, elf_init.GNUVerSym, elf_init.GNUVerNeed + )): + log.debug("Find GNU version related section, unsupported for now") + + for section in symbol_sections: + for symbol_entry in section.symtab: + # Here, the computation of vaddr assumes 'elf' is an executable or a + # shared object file + + # For relocatable file, symbol_entry.value is an offset from the section + # base -> not handled here + st_bind = symbol_entry.info >> 4 + st_type = symbol_entry.info & 0xF + + if st_type not in [ + elf_csts.STT_NOTYPE, + elf_csts.STT_OBJECT, + elf_csts.STT_FUNC, + elf_csts.STT_COMMON, + elf_csts.STT_GNU_IFUNC, + ]: + # Ignore symbols useless in linking + continue + + if st_bind == elf_csts.STB_GLOBAL: + # Global symbol + weak = False + elif st_bind == elf_csts.STB_WEAK: + # Weak symbol + weak = True + else: + # Ignore local & others symbols + continue + + absolute = False + if symbol_entry.shndx == 0: + # SHN_UNDEF + continue + elif symbol_entry.shndx == 0xfff1: + # SHN_ABS + absolute = True + log.debug("Absolute symbol %r - %x", symbol_entry.name, + symbol_entry.value) + elif 0xff00 <= symbol_entry.shndx <= 0xffff: + # Reserved index (between SHN_LORESERV and SHN_HIRESERVE) + raise RuntimeError("Unsupported reserved index: %r" % symbol_entry) + + name = force_str(symbol_entry.name) + if name == "": + # Ignore empty symbol + log.debug("Empty symbol %r", symbol_entry) + continue + + if absolute: + vaddr = symbol_entry.value + else: + vaddr = symbol_entry.value + base_addr + + # 'weak' information is only used to force global symbols for now + already_existing_loc = loc_db.get_name_location(name) + if already_existing_loc is not None: + if weak: + # Weak symbol, this is ok to already exists, skip it + continue + else: + # Global symbol, force it + loc_db.remove_location_name(already_existing_loc, + name) + already_existing_off = loc_db.get_offset_location(vaddr) + if already_existing_off is not None: + loc_db.add_location_name(already_existing_off, name) + else: + loc_db.add_location(name=name, offset=vaddr) + + +def apply_reloc_x86(elf, vm, section, base_addr, loc_db): + """Apply relocation for x86 ELF contained in the section @section + @elf: miasm.loader's ELF instance + @vm: VmMngr instance + @section: elf's section containing relocation to perform + @base_addr: addr to reloc to + @loc_db: LocationDB used to retrieve symbols'offset + """ + if elf.size == 64: + addr_writer = lambda vaddr, addr: vm.set_mem(vaddr, + struct.pack("<Q", addr)) + elif elf.size == 32: + addr_writer = lambda vaddr, addr: vm.set_mem(vaddr, + struct.pack("<I", addr)) + else: + raise ValueError("Unsupported elf size %d" % elf.size) + + symb_section = section.linksection + for reloc in section.reltab: + + # Parse relocation info + r_info = reloc.info + if elf.size == 64: + r_info_sym = (r_info >> 32) & 0xFFFFFFFF + r_info_type = r_info & 0xFFFFFFFF + elif elf.size == 32: + r_info_sym = (r_info >> 8) & 0xFFFFFF + r_info_type = r_info & 0xFF + + is_ifunc = False + symbol_entry = None + if r_info_sym > 0: + symbol_entry = symb_section.symtab[r_info_sym] + + r_offset = reloc.offset + r_addend = reloc.cstr.sym + + if (elf.size, reloc.type) in [ + (64, elf_csts.R_X86_64_RELATIVE), + (64, elf_csts.R_X86_64_IRELATIVE), + (32, elf_csts.R_386_RELATIVE), + (32, elf_csts.R_386_IRELATIVE), + ]: + # B + A + addr = base_addr + r_addend + where = base_addr + r_offset + elif reloc.type == elf_csts.R_X86_64_64: + # S + A + addr_symb = loc_db.get_name_offset(symbol_entry.name) + if addr_symb is None: + log.warning("Unable to find symbol %r" % symbol_entry.name) + continue + addr = addr_symb + r_addend + where = base_addr + r_offset + elif (elf.size, reloc.type) in [ + (64, elf_csts.R_X86_64_TPOFF64), + (64, elf_csts.R_X86_64_DTPMOD64), + (32, elf_csts.R_386_TLS_TPOFF), + ]: + # Thread dependent, ignore for now + log.debug("Skip relocation TPOFF64 %r", reloc) + continue + elif (elf.size, reloc.type) in [ + (64, elf_csts.R_X86_64_GLOB_DAT), + (64, elf_csts.R_X86_64_JUMP_SLOT), + (32, elf_csts.R_386_JMP_SLOT), + (32, elf_csts.R_386_GLOB_DAT), + ]: + # S + addr = loc_db.get_name_offset(symbol_entry.name) + if addr is None: + log.warning("Unable to find symbol %r" % symbol_entry.name) + continue + is_ifunc = symbol_entry.info & 0xF == elf_csts.STT_GNU_IFUNC + where = base_addr + r_offset + else: + raise ValueError( + "Unknown relocation type: %d (%r)" % (reloc.type, + reloc) + ) + if is_ifunc: + # Resolve at runtime - not implemented for now + log.warning("Relocation for %r (at %x, currently pointing on %x) " + "has to be resolved at runtime", + name, where, sym_addr) + continue + + log.debug("Write %x at %x", addr, where) + addr_writer(where, addr) + + +def vm_load_elf(vm, fdata, name="", base_addr=0, loc_db=None, apply_reloc=False, + **kargs): + """ + Very dirty elf loader + TODO XXX: implement real loader + """ + elf = elf_init.ELF(fdata, **kargs) + i = interval() + all_data = {} + + for p in elf.ph.phlist: + if p.ph.type != elf_csts.PT_LOAD: + continue + log.debug( + '0x%x 0x%x 0x%x 0x%x 0x%x', p.ph.vaddr, p.ph.memsz, p.ph.offset, + p.ph.filesz, p.ph.type) + data_o = elf._content[p.ph.offset:p.ph.offset + p.ph.filesz] + addr_o = p.ph.vaddr + base_addr + a_addr = addr_o & ~0xFFF + b_addr = addr_o + max(p.ph.memsz, p.ph.filesz) + b_addr = (b_addr + 0xFFF) & ~0xFFF + all_data[addr_o] = data_o + # -2: Trick to avoid merging 2 consecutive pages + i += [(a_addr, b_addr - 2)] + for a, b in i.intervals: + vm.add_memory_page( + a, + PAGE_READ | PAGE_WRITE, + b"\x00" * (b + 2 - a), + repr(name) + ) + + for r_vaddr, data in viewitems(all_data): + vm.set_mem(r_vaddr, data) + + if loc_db is not None: + fill_loc_db_with_symbols(elf, loc_db, base_addr) + + if apply_reloc: + arch = guess_arch(elf) + sections = [] + for section in elf.sh: + if not hasattr(section, 'reltab'): + continue + if isinstance(section, elf_init.RelATable): + pass + elif isinstance(section, elf_init.RelTable): + if arch == "x86_64": + log.warning("REL section should not happen in x86_64") + else: + raise RuntimeError("Unknown relocation section type: %r" % section) + sections.append(section) + for section in sections: + if arch in ["x86_64", "x86_32"]: + apply_reloc_x86(elf, vm, section, base_addr, loc_db) + else: + log.debug("Unsupported relocation for arch %r" % arch) + + return elf + + +class libimp_elf(libimp): + pass + + +# machine, size, sex -> arch_name +ELF_machine = {(elf_csts.EM_ARM, 32, elf_csts.ELFDATA2LSB): "arml", + (elf_csts.EM_ARM, 32, elf_csts.ELFDATA2MSB): "armb", + (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2LSB): "aarch64l", + (elf_csts.EM_AARCH64, 64, elf_csts.ELFDATA2MSB): "aarch64b", + (elf_csts.EM_MIPS, 32, elf_csts.ELFDATA2MSB): "mips32b", + (elf_csts.EM_MIPS, 32, elf_csts.ELFDATA2LSB): "mips32l", + (elf_csts.EM_386, 32, elf_csts.ELFDATA2LSB): "x86_32", + (elf_csts.EM_X86_64, 64, elf_csts.ELFDATA2LSB): "x86_64", + (elf_csts.EM_SH, 32, elf_csts.ELFDATA2LSB): "sh4", + (elf_csts.EM_PPC, 32, elf_csts.ELFDATA2MSB): "ppc32b", + } + + +def guess_arch(elf): + """Return the architecture specified by the ELF container @elf. + If unknown, return None""" + return ELF_machine.get((elf.Ehdr.machine, elf.size, elf.sex), None) diff --git a/src/miasm/jitter/loader/pe.py b/src/miasm/jitter/loader/pe.py new file mode 100644 index 00000000..9af068e4 --- /dev/null +++ b/src/miasm/jitter/loader/pe.py @@ -0,0 +1,834 @@ +from builtins import map +import os +import struct +import logging +from collections import defaultdict + +from future.utils import viewitems, viewvalues + +from miasm.loader import pe +from miasm.loader import cstruct +from miasm.loader import * + +from miasm.jitter.csts import * +from miasm.jitter.loader.utils import canon_libname_libfunc, libimp +from miasm.core.utils import force_str + +log = logging.getLogger('loader_pe') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.INFO) + + +def get_pe_dependencies(pe_obj): + """Collect the shared libraries upon which this PE depends. + + @pe_obj: pe object + Returns a set of strings of DLL names. + + Example: + + pe = miasm.analysis.binary.Container.from_string(buf) + deps = miasm.jitter.loader.pe.get_pe_dependencies(pe.executable) + assert sorted(deps)[0] == 'api-ms-win-core-appcompat-l1-1-0.dll' + """ + + if pe_obj.DirImport.impdesc is None: + return set() + out = set() + for dependency in pe_obj.DirImport.impdesc: + libname = dependency.dlldescname.name.lower() + # transform bytes to str + libname = force_str(libname) + out.add(libname) + + # If binary has redirected export, add dependencies + if pe_obj.DirExport.expdesc != None: + addrs = get_export_name_addr_list(pe_obj) + for imp_ord_or_name, ad in addrs: + # if export is a redirection, search redirected dll + # and get function real addr + ret = is_redirected_export(pe_obj, ad) + if ret is False: + continue + dllname, func_info = ret + dllname = dllname + '.dll' + out.add(dllname) + + return out + + +def get_import_address_pe(e): + """Compute the addresses of imported symbols. + @e: pe object + Returns a dict mapping from tuple (dll name string, symbol name string) to set of virtual addresses. + + Example: + + pe = miasm.analysis.binary.Container.from_string(buf) + imports = miasm.jitter.loader.pe.get_import_address_pe(pe.executable) + assert imports[('api-ms-win-core-rtlsupport-l1-1-0.dll', 'RtlCaptureStackBackTrace')] == {0x6b88a6d0} + """ + import2addr = defaultdict(set) + if e.DirImport.impdesc is None: + return import2addr + for s in e.DirImport.impdesc: + # fthunk = e.rva2virt(s.firstthunk) + # l = "%2d %-25s %s" % (i, repr(s.dlldescname), repr(s)) + libname = force_str(s.dlldescname.name.lower()) + + for ii, imp in enumerate(s.impbynames): + if isinstance(imp, pe.ImportByName): + funcname = force_str(imp.name) + else: + funcname = imp + # l = " %2d %-16s" % (ii, repr(funcname)) + import2addr[(libname, funcname)].add( + e.rva2virt(s.firstthunk + (e._wsize * ii) // 8) + ) + return import2addr + + +def preload_pe(vm, e, runtime_lib, patch_vm_imp=True): + fa = get_import_address_pe(e) + dyn_funcs = {} + # log.debug('imported funcs: %s' % fa) + for (libname, libfunc), ads in viewitems(fa): + for ad in ads: + libname = force_str(libname) + ad_base_lib = runtime_lib.lib_get_add_base(libname) + ad_libfunc = runtime_lib.lib_get_add_func(ad_base_lib, libfunc, ad) + + libname_s = canon_libname_libfunc(libname, libfunc) + dyn_funcs[libname_s] = ad_libfunc + if patch_vm_imp: + vm.set_mem( + ad, struct.pack(cstruct.size2type[e._wsize], ad_libfunc)) + return dyn_funcs + + +def is_redirected_export(pe_obj, addr): + """Test if the @addr is a forwarded export address. If so, return + dllname/function name couple. If not, return False. + + An export address is a forwarded export if the rva is in the export + directory of the pe. + + @pe_obj: PE instance + @addr: virtual address of the function to test + """ + + export_dir = pe_obj.NThdr.optentries[pe.DIRECTORY_ENTRY_EXPORT] + addr_rva = pe_obj.virt2rva(addr) + if not (export_dir.rva <= addr_rva < export_dir.rva + export_dir.size): + return False + addr_end = pe_obj.virt.find(b'\x00', addr) + data = pe_obj.virt.get(addr, addr_end) + + data = force_str(data) + dllname, func_info = data.split('.', 1) + dllname = dllname.lower() + + # Test if function is forwarded using ordinal + if func_info.startswith('#'): + func_info = int(func_info[1:]) + return dllname, func_info + + +def get_export_name_addr_list(e): + """Collect names/ordinals and addresses of symbols exported by the given PE. + @e: PE instance + Returns a list of tuples: + (symbol name string, virtual address) + (ordinal number, virtual address) + + Example: + + pe = miasm.analysis.binary.Container.from_string(buf) + exports = miasm.jitter.loader.pe.get_export_name_addr_list(pe.executable) + assert exports[0] == ('AcquireSRWLockExclusive', 0x6b89b22a) + """ + out = [] + if e.DirExport.expdesc is None: + return out + + # add func name + for i, n in enumerate(e.DirExport.f_names): + addr = e.DirExport.f_address[e.DirExport.f_nameordinals[i].ordinal] + f_name = force_str(n.name.name) + # log.debug('%s %s' % (f_name, hex(e.rva2virt(addr.rva)))) + out.append((f_name, e.rva2virt(addr.rva))) + + # add func ordinal + for i, s in enumerate(e.DirExport.f_address): + if not s.rva: + continue + out.append((i + e.DirExport.expdesc.base, e.rva2virt(s.rva))) + + return out + + +def vm_load_pe(vm, fdata, align_s=True, load_hdr=True, name="", winobjs=None, **kargs): + """Load a PE in memory (@vm) from a data buffer @fdata + @vm: VmMngr instance + @fdata: data buffer to parse + @align_s: (optional) If False, keep gaps between section + @load_hdr: (optional) If False, do not load the NThdr in memory + Return the corresponding PE instance. + + Extra arguments are passed to PE instantiation. + If all sections are aligned, they will be mapped on several different pages + Otherwise, a big page is created, containing all sections + """ + + # Parse and build a PE instance + pe = pe_init.PE(fdata, **kargs) + + # Check if all section are aligned + aligned = True + for section in pe.SHList: + if section.addr & 0xFFF: + aligned = False + break + + if aligned: + # Loader NT header + if load_hdr: + # Header length + hdr_len = max(0x200, pe.NThdr.sizeofheaders) + # Page minimum size + min_len = min(pe.SHList[0].addr, 0x1000) + + # Get and pad the pe_hdr + pe_hdr = ( + pe.content[:hdr_len] + + max(0, (min_len - hdr_len)) * b"\x00" + ) + + if winobjs: + winobjs.allocated_pages[pe.NThdr.ImageBase] = (pe.NThdr.ImageBase, len(pe_hdr)) + vm.add_memory_page( + pe.NThdr.ImageBase, + PAGE_READ | PAGE_WRITE, + pe_hdr, + "%r: PE Header" % name + ) + + # Align sections size + if align_s: + # Use the next section address to compute the new size + for i, section in enumerate(pe.SHList[:-1]): + new_size = pe.SHList[i + 1].addr - section.addr + section.size = new_size + section.rawsize = new_size + section.data = strpatchwork.StrPatchwork( + section.data[:new_size] + ) + section.offset = section.addr + + # Last section alignment + last_section = pe.SHList[-1] + last_section.size = (last_section.size + 0xfff) & 0xfffff000 + + # Pad sections with null bytes and map them + for section in pe.SHList: + data = bytes(section.data) + data += b"\x00" * (section.size - len(data)) + attrib = PAGE_READ + if section.flags & 0x80000000: + attrib |= PAGE_WRITE + + section_addr = pe.rva2virt(section.addr) + if winobjs: + winobjs.allocated_pages[section_addr] = (section_addr, len(data)) + vm.add_memory_page( + section_addr, + attrib, + data, + "%r: %r" % (name, section.name) + ) + + return pe + + # At least one section is not aligned + log.warning('PE is not aligned, creating big section') + min_addr = 0 if load_hdr else None + max_addr = None + data = "" + + for i, section in enumerate(pe.SHList): + if i < len(pe.SHList) - 1: + # If it is not the last section, use next section address + section.size = pe.SHList[i + 1].addr - section.addr + section.rawsize = section.size + section.offset = section.addr + + # Update min and max addresses + if min_addr is None or section.addr < min_addr: + min_addr = section.addr + max_section_len = max(section.size, len(section.data)) + if max_addr is None or section.addr + max_section_len > max_addr: + max_addr = section.addr + max_section_len + + min_addr = pe.rva2virt(min_addr) + max_addr = pe.rva2virt(max_addr) + log.debug('Min: 0x%x, Max: 0x%x, Size: 0x%x', min_addr, max_addr, + (max_addr - min_addr)) + + # Create only one big section containing the whole PE + vm.add_memory_page( + min_addr, + PAGE_READ | PAGE_WRITE, + (max_addr - min_addr) * b"\x00" + ) + + # Copy each sections content in memory + for section in pe.SHList: + log.debug('Map 0x%x bytes to 0x%x', len(section.data), + pe.rva2virt(section.addr)) + vm.set_mem(pe.rva2virt(section.addr), bytes(section.data)) + + return pe + + +def vm_load_pe_lib(vm, fname_in, libs, lib_path_base, **kargs): + """Call vm_load_pe on @fname_in and update @libs accordingly + @vm: VmMngr instance + @fname_in: library name + @libs: libimp_pe instance + @lib_path_base: DLLs relative path + Return the corresponding PE instance + Extra arguments are passed to vm_load_pe + """ + + log.info('Loading module %r', fname_in) + + fname = os.path.join(lib_path_base, fname_in) + with open(fname, "rb") as fstream: + pe = vm_load_pe(vm, fstream.read(), name=fname_in, **kargs) + libs.add_export_lib(pe, fname_in) + return pe + + +def vm_load_pe_libs(vm, libs_name, libs, lib_path_base, **kargs): + """Call vm_load_pe_lib on each @libs_name filename + @vm: VmMngr instance + @libs_name: list of str + @libs: libimp_pe instance + @lib_path_base: (optional) DLLs relative path + Return a dictionary Filename -> PE instances + Extra arguments are passed to vm_load_pe_lib + """ + out = {} + for fname in libs_name: + assert isinstance(fname, str) + out[fname] = vm_load_pe_lib(vm, fname, libs, lib_path_base, **kargs) + return out + + +def vm_fix_imports_pe_libs(lib_imgs, libs, lib_path_base, + patch_vm_imp=True, **kargs): + for e in viewvalues(lib_imgs): + preload_pe(e, libs, patch_vm_imp) + + +def vm2pe(myjit, fname, libs=None, e_orig=None, + min_addr=None, max_addr=None, + min_section_offset=0x1000, img_base=None, + added_funcs=None, **kwargs): + if e_orig: + size = e_orig._wsize + else: + size = 32 + mye = pe_init.PE(wsize=size) + + if min_addr is None and e_orig is not None: + min_addr = min([e_orig.rva2virt(s.addr) for s in e_orig.SHList]) + if max_addr is None and e_orig is not None: + max_addr = max([e_orig.rva2virt(s.addr + s.size) + for s in e_orig.SHList]) + + if img_base is None: + img_base = e_orig.NThdr.ImageBase + + mye.NThdr.ImageBase = img_base + all_mem = myjit.vm.get_all_memory() + addrs = list(all_mem) + addrs.sort() + entry_point = mye.virt2rva(myjit.pc) + if entry_point is None or not 0 < entry_point < 0xFFFFFFFF: + raise ValueError( + "Current pc (0x%x) used as entry point seems to be out of the binary" % + myjit.pc + ) + + mye.Opthdr.AddressOfEntryPoint = entry_point + first = True + for ad in addrs: + if not min_addr <= ad < max_addr: + continue + log.debug("0x%x", ad) + if first: + mye.SHList.add_section( + "%.8X" % ad, + addr=ad - mye.NThdr.ImageBase, + data=all_mem[ad]['data'], + offset=min_section_offset) + else: + mye.SHList.add_section( + "%.8X" % ad, + addr=ad - mye.NThdr.ImageBase, + data=all_mem[ad]['data']) + first = False + if libs: + if added_funcs is not None: + for addr, funcaddr in added_funcs: + libbase, dllname = libs.fad2info[funcaddr] + libs.lib_get_add_func(libbase, dllname, addr) + + filter_import = kwargs.get( + 'filter_import', lambda _, ad: mye.virt.is_addr_in(ad)) + new_dll = libs.gen_new_lib(mye, filter_import) + else: + new_dll = {} + + log.debug('%s', new_dll) + + mye.DirImport.add_dlldesc(new_dll) + s_imp = mye.SHList.add_section("import", rawsize=len(mye.DirImport)) + mye.DirImport.set_rva(s_imp.addr) + log.debug('%r', mye.SHList) + if e_orig: + # resource + xx = bytes(mye) + mye.content = xx + ad = e_orig.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva + size = e_orig.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].size + log.debug('dirres 0x%x', ad) + if ad != 0: + mye.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].rva = ad + mye.NThdr.optentries[pe.DIRECTORY_ENTRY_RESOURCE].size = size + mye.DirRes = pe.DirRes.unpack(mye.img_rva, ad, mye) + log.debug('%r', mye.DirRes) + s_res = mye.SHList.add_section( + name="myres", + rawsize=len(mye.DirRes) + ) + mye.DirRes.set_rva(s_res.addr) + # generation + open(fname, 'wb').write(bytes(mye)) + return mye + + +class libimp_pe(libimp): + + def __init__(self, *args, **kwargs): + super(libimp_pe, self).__init__(*args, **kwargs) + # dependency -> redirector + self.created_redirected_imports = {} + + + def add_function(self, dllname, imp_ord_or_name, addr): + assert isinstance(dllname, str) + assert isinstance(imp_ord_or_name, (int, str)) + libad = self.name2off[dllname] + c_name = canon_libname_libfunc( + dllname, imp_ord_or_name + ) + update_entry = True + if addr in self.fad2info: + known_libad, known_imp_ord_or_name = self.fad2info[addr] + if isinstance(imp_ord_or_name, int): + update_entry = False + self.cname2addr[c_name] = addr + log.debug("Add func %s %s", hex(addr), c_name) + if update_entry: + log.debug("Real Add func %s %s", hex(addr), c_name) + self.fad2cname[addr] = c_name + self.fad2info[addr] = libad, imp_ord_or_name + + + def add_export_lib(self, e, name): + if name in self.created_redirected_imports: + log.error("%r has previously been created due to redirect\ + imports due to %r. Change the loading order.", + name, self.created_redirected_imports[name]) + raise RuntimeError('Bad import: loading previously created import') + + self.all_exported_lib.append(e) + # will add real lib addresses to database + if name in self.name2off: + ad = self.name2off[name] + if e is not None and name in self.fake_libs: + log.error( + "You are trying to load %r but it has been faked previously. Try loading this module earlier.", name) + raise RuntimeError("Bad import") + else: + log.debug('new lib %s', name) + ad = e.NThdr.ImageBase + libad = ad + self.name2off[name] = ad + self.libbase2lastad[ad] = ad + 0x1 + self.lib_imp2ad[ad] = {} + self.lib_imp2dstad[ad] = {} + self.libbase_ad += 0x1000 + + ads = get_export_name_addr_list(e) + todo = list(ads) + # done = [] + while todo: + # for imp_ord_or_name, ad in ads: + imp_ord_or_name, ad = todo.pop() + + # if export is a redirection, search redirected dll + # and get function real addr + ret = is_redirected_export(e, ad) + if ret: + exp_dname, exp_fname = ret + exp_dname = exp_dname + '.dll' + exp_dname = exp_dname.lower() + # if dll auto refes in redirection + if exp_dname == name: + libad_tmp = self.name2off[exp_dname] + if isinstance(exp_fname, str): + exp_fname = bytes(ord(c) for c in exp_fname) + found = None + for tmp_func, tmp_addr in ads: + if tmp_func == exp_fname: + found = tmp_addr + assert found is not None + ad = found + else: + # import redirected lib from non loaded dll + if not exp_dname in self.name2off: + self.created_redirected_imports.setdefault( + exp_dname, set()).add(name) + + # Ensure import entry is created + new_lib_base = self.lib_get_add_base(exp_dname) + # Ensure function entry is created + _ = self.lib_get_add_func(new_lib_base, exp_fname) + + libad_tmp = self.name2off[exp_dname] + ad = self.lib_imp2ad[libad_tmp][exp_fname] + + self.lib_imp2ad[libad][imp_ord_or_name] = ad + name_inv = dict( + (value, key) for key, value in viewitems(self.name2off) + ) + c_name = canon_libname_libfunc( + name_inv[libad], imp_ord_or_name) + self.fad2cname[ad] = c_name + self.cname2addr[c_name] = ad + log.debug("Add func %s %s", hex(ad), c_name) + self.fad2info[ad] = libad, imp_ord_or_name + + def gen_new_lib(self, target_pe, filter_import=lambda peobj, ad: True, **kwargs): + """Gen a new DirImport description + @target_pe: PE instance + @filter_import: (boolean f(pe, address)) restrict addresses to keep + """ + + new_lib = [] + for lib_name, ad in viewitems(self.name2off): + # Build an IMAGE_IMPORT_DESCRIPTOR + + # Get fixed addresses + out_ads = dict() # addr -> func_name + for func_name, dst_addresses in viewitems(self.lib_imp2dstad[ad]): + out_ads.update({addr: func_name for addr in dst_addresses}) + + # Filter available addresses according to @filter_import + all_ads = [ + addr for addr in list(out_ads) if filter_import(target_pe, addr) + ] + + if not all_ads: + continue + + # Keep non-NULL elements + all_ads.sort(key=str) + for i, x in enumerate(all_ads): + if x not in [0, None]: + break + all_ads = all_ads[i:] + log.debug('ads: %s', list(map(hex, all_ads))) + + while all_ads: + # Find libname's Import Address Table + othunk = all_ads[0] + i = 0 + while (i + 1 < len(all_ads) and + all_ads[i] + target_pe._wsize // 8 == all_ads[i + 1]): + i += 1 + # 'i + 1' is IAT's length + + # Effectively build an IMAGE_IMPORT_DESCRIPTOR + funcs = [out_ads[addr] for addr in all_ads[:i + 1]] + try: + rva = target_pe.virt2rva(othunk) + except pe.InvalidOffset: + pass + else: + new_lib.append(({"name": lib_name, + "firstthunk": rva}, + funcs) + ) + + # Update elements to handle + all_ads = all_ads[i + 1:] + + return new_lib + + +def vm_load_pe_and_dependencies(vm, fname, name2module, runtime_lib, + lib_path_base, **kwargs): + """Load a binary and all its dependencies. Returns a dictionary containing + the association between binaries names and it's pe object + + @vm: virtual memory manager instance + @fname: full path of the binary + @name2module: dict containing association between name and pe + object. Updated. + @runtime_lib: libimp instance + @lib_path_base: directory of the libraries containing dependencies + + """ + + todo = [(fname, fname, 0)] + weight2name = {} + done = set() + + # Walk dependencies recursively + while todo: + name, fname, weight = todo.pop() + if name in done: + continue + done.add(name) + weight2name.setdefault(weight, set()).add(name) + if name in name2module: + pe_obj = name2module[name] + else: + try: + with open(fname, "rb") as fstream: + log.info('Loading module name %r', fname) + pe_obj = vm_load_pe( + vm, fstream.read(), name=fname, **kwargs) + except IOError: + log.error('Cannot open %s' % fname) + name2module[name] = None + continue + name2module[name] = pe_obj + + new_dependencies = get_pe_dependencies(pe_obj) + todo += [(name, os.path.join(lib_path_base, name), weight - 1) + for name in new_dependencies] + + known_export_addresses = {} + to_resolve = {} + for name, pe_obj in name2module.items(): + print(name) + if pe_obj is None: + continue + if pe_obj.DirExport.expdesc == None: + continue + addrs = get_export_name_addr_list(pe_obj) + for imp_ord_or_name, ad in addrs: + # if export is a redirection, search redirected dll + # and get function real addr + ret = is_redirected_export(pe_obj, ad) + if ret is False: + known_export_addresses[(name, imp_ord_or_name)] = ad + else: + dllname, func_info = ret + dllname = dllname + '.dll' + to_resolve[(name, imp_ord_or_name)] = (dllname, func_info) + + modified = True + while modified: + modified = False + out = {} + for target, dependency in to_resolve.items(): + dllname, funcname = dependency + if dependency in known_export_addresses: + known_export_addresses[target] = known_export_addresses[dependency] + modified = True + else: + log.error("Cannot resolve redirection %r %r", dllname, dependency) + raise RuntimeError('Cannot resolve redirection') + to_resolve = out + + for dllname, pe_obj in name2module.items(): + if pe_obj is None: + continue + ad = pe_obj.NThdr.ImageBase + libad = ad + runtime_lib.name2off[dllname] = ad + runtime_lib.libbase2lastad[ad] = ad + 0x1 + runtime_lib.lib_imp2ad[ad] = {} + runtime_lib.lib_imp2dstad[ad] = {} + runtime_lib.libbase_ad += 0x1000 + + for (dllname, imp_ord_or_name), addr in known_export_addresses.items(): + runtime_lib.add_function(dllname, imp_ord_or_name, addr) + libad = runtime_lib.name2off[dllname] + runtime_lib.lib_imp2ad[libad][imp_ord_or_name] = addr + + assert not to_resolve + + for dllname, pe_obj in name2module.items(): + if pe_obj is None: + continue + preload_pe(vm, pe_obj, runtime_lib, patch_vm_imp=True) + + return name2module + +# machine -> arch +PE_machine = { + 0x14c: "x86_32", + 0x8664: "x86_64", +} + + +def guess_arch(pe): + """Return the architecture specified by the PE container @pe. + If unknown, return None""" + return PE_machine.get(pe.Coffhdr.machine, None) + + +class ImpRecStateMachine(object): + """ + Finite State Machine used for internal purpose only. + See `ImpRecStrategy` for more details. + """ + + # Looking for a function pointer + STATE_SEARCH = 0 + # Candidate function list + STATE_FUNC_FOUND = 1 + # Function list found, terminated by a NULL entry + STATE_END_FUNC_LIST = 2 + + def __init__(self, libs, ptrtype): + self.ptrtype = ptrtype + self.libs = libs + self.func_addrs = set(struct.pack(self.ptrtype, address) for address in self.libs.cname2addr.values()) + self.off2name = {v:k for k,v in self.libs.name2off.items()} + self.state = self.STATE_SEARCH + + # STATE_FUNC_FOUND + self.cur_list = [] + self.cur_list_lib = None + + # STATE_END_FUNC_LIST + self.seen = [] + + def format_func_info(self, func_info, func_addr): + return { + "lib_addr": func_info[0], + "lib_name": self.off2name[func_info[0]], + "entry_name": func_info[1], + "entry_module_addr": func_addr, + "entry_memory_addr": self.cur_address, + } + + def transition(self, data): + if self.state == self.STATE_SEARCH: + if data in self.func_addrs: + self.state = self.STATE_FUNC_FOUND + func_addr = struct.unpack(self.ptrtype, data)[0] + func_info = self.libs.fad2info[func_addr] + self.cur_list = [self.format_func_info(func_info, func_addr)] + self.cur_list_lib = func_info[0] + elif self.state == self.STATE_FUNC_FOUND: + if data == (b"\x00" * len(data)): + self.state = self.STATE_END_FUNC_LIST + elif data in self.func_addrs: + func_addr = struct.unpack(self.ptrtype, data)[0] + func_info = self.libs.fad2info[func_addr] + if func_info[0] != self.cur_list_lib: + # The list must belong to the same library + self.state = self.STATE_SEARCH + return + self.cur_list.append(self.format_func_info(func_info, func_addr)) + else: + self.state == self.STATE_SEARCH + elif self.state == self.STATE_END_FUNC_LIST: + self.seen.append(self.cur_list) + self.state = self.STATE_SEARCH + self.transition(data) + else: + raise ValueError() + + def run(self): + while True: + data, address = yield + self.cur_address = address + self.transition(data) + + +class ImpRecStrategy(object): + """ + Naive import reconstruction, similar to ImpRec + + It looks for a continuation of module export addresses, ended by a NULL entry, ie: + [...] + &Kernel32::LoadLibraryA + &Kernel32::HeapCreate + 00 00 00 00 + [...] + + Usage: + >>> sb = Sandbox[...] + >>> sb.run() + >>> imprec = ImpRecStrategy(sb.jitter, sb.libs, size=32) + >>> imprec.recover_import() + List<List<Recovered functions>> + + -> sb.libs has also been updated, ready to be passed to `vm2pe` + """ + def __init__(self, jitter, libs, size): + self._jitter = jitter + self._libs = libs + if size == 32: + self._ptrtype = "<I" + elif size == 64: + self._ptrtype = "<Q" + else: + ValueError("Unsupported size: %d" % size) + + def recover_import(self, update_libs=True, align_hypothesis=False): + """ + Launch the import recovery routine. + @update_libs: if set (default), update `libs` object with founded addresses + @align_hypothesis: if not set (default), do not consider import + addresses are written on aligned addresses + + Return the list of candidates + """ + candidates = [] + + alignments = [0] + if not align_hypothesis: + alignments = list(range(0, struct.calcsize(self._ptrtype))) + + for starting_offset in alignments: + # Search for several addresses from `func_addrs` ending with a `\x00` + fsm_obj = ImpRecStateMachine(self._libs, self._ptrtype) + fsm = fsm_obj.run() + fsm.send(None) + for addr_start, page_info in self._jitter.vm.get_all_memory().items(): + data = page_info["data"] + for i in range(starting_offset, page_info["size"], struct.calcsize(self._ptrtype)): + fsm.send((data[i:i+4], addr_start + i)) + + candidates.extend(fsm_obj.seen) + + # Apply to libs + if update_libs: + for entry_list in candidates: + for func_info in entry_list: + self._libs.lib_imp2dstad[func_info["lib_addr"]][func_info["entry_name"]].add(func_info["entry_memory_addr"]) + + return candidates diff --git a/src/miasm/jitter/loader/utils.py b/src/miasm/jitter/loader/utils.py new file mode 100644 index 00000000..7f913d76 --- /dev/null +++ b/src/miasm/jitter/loader/utils.py @@ -0,0 +1,100 @@ +from builtins import int as int_types +import logging + +from future.utils import viewitems, viewvalues +from past.builtins import basestring + +log = logging.getLogger('loader_common') +hnd = logging.StreamHandler() +hnd.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s")) +log.addHandler(hnd) +log.setLevel(logging.INFO) + + +def canon_libname_libfunc(libname, libfunc): + assert isinstance(libname, basestring) + assert isinstance(libfunc, basestring) or isinstance(libfunc, int_types) + dn = libname.split('.')[0] + if isinstance(libfunc, int_types): + return str(dn), libfunc + else: + return "%s_%s" % (dn, libfunc) + + +class libimp(object): + + def __init__(self, lib_base_ad=0x71111000, **kargs): + self.name2off = {} + self.libbase2lastad = {} + self.libbase_ad = lib_base_ad + self.lib_imp2ad = {} + self.lib_imp2dstad = {} + self.fad2cname = {} + self.cname2addr = {} + self.fad2info = {} + self.all_exported_lib = [] + self.fake_libs = set() + + def lib_get_add_base(self, name): + assert isinstance(name, basestring) + name = name.lower().strip(' ') + if not "." in name: + log.warning('warning adding .dll to modulename') + name += '.dll' + log.warning(name) + + if name in self.name2off: + ad = self.name2off[name] + else: + ad = self.libbase_ad + log.warning("Create dummy entry for %r", name) + self.fake_libs.add(name) + self.name2off[name] = ad + self.libbase2lastad[ad] = ad + 0x4 + self.lib_imp2ad[ad] = {} + self.lib_imp2dstad[ad] = {} + self.libbase_ad += 0x1000 + return ad + + def lib_get_add_func(self, libad, imp_ord_or_name, dst_ad=None): + if not libad in viewvalues(self.name2off): + raise ValueError('unknown lib base!', hex(libad)) + + # test if not ordinatl + # if imp_ord_or_name >0x10000: + # imp_ord_or_name = vm_get_str(imp_ord_or_name, 0x100) + # imp_ord_or_name = imp_ord_or_name[:imp_ord_or_name.find('\x00')] + + #[!] can have multiple dst ad + if not imp_ord_or_name in self.lib_imp2dstad[libad]: + self.lib_imp2dstad[libad][imp_ord_or_name] = set() + if dst_ad is not None: + self.lib_imp2dstad[libad][imp_ord_or_name].add(dst_ad) + + if imp_ord_or_name in self.lib_imp2ad[libad]: + return self.lib_imp2ad[libad][imp_ord_or_name] + log.debug('new imp %s %s' % (imp_ord_or_name, dst_ad)) + ad = self.libbase2lastad[libad] + self.libbase2lastad[libad] += 0x10 # arbitrary + self.lib_imp2ad[libad][imp_ord_or_name] = ad + + name_inv = dict( + (value, key) for key, value in viewitems(self.name2off) + ) + c_name = canon_libname_libfunc(name_inv[libad], imp_ord_or_name) + self.fad2cname[ad] = c_name + self.cname2addr[c_name] = ad + self.fad2info[ad] = libad, imp_ord_or_name + return ad + + def check_dst_ad(self): + for ad in self.lib_imp2dstad: + all_ads = sorted(viewvalues(self.lib_imp2dstad[ad])) + for i, x in enumerate(all_ads[:-1]): + if x is None or all_ads[i + 1] is None: + return False + if x + 4 != all_ads[i + 1]: + return False + return True + + diff --git a/src/miasm/jitter/op_semantics.c b/src/miasm/jitter/op_semantics.c new file mode 100644 index 00000000..6725ae64 --- /dev/null +++ b/src/miasm/jitter/op_semantics.c @@ -0,0 +1,853 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> +#include <math.h> +#include "op_semantics.h" + +const uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +uint16_t bcdadd_16(uint16_t a, uint16_t b) +{ + int carry = 0; + int i,j = 0; + uint16_t res = 0; + int nib_a, nib_b; + for (i = 0; i < 16; i += 4) { + nib_a = (a >> i) & (0xF); + nib_b = (b >> i) & (0xF); + + j = (carry + nib_a + nib_b); + if (j >= 10) { + carry = 1; + j -= 10; + j &=0xf; + } + else { + carry = 0; + } + res += j << i; + } + return res; +} + +uint16_t bcdadd_cf_16(uint16_t a, uint16_t b) +{ + int carry = 0; + int i,j = 0; + int nib_a, nib_b; + for (i = 0; i < 16; i += 4) { + nib_a = (a >> i) & (0xF); + nib_b = (b >> i) & (0xF); + + j = (carry + nib_a + nib_b); + if (j >= 10) { + carry = 1; + j -= 10; + j &=0xf; + } + else { + carry = 0; + } + } + return carry; +} + +unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b) +{ + unsigned int mask; + + switch (size) { + case 8: mask = 0xff; break; + case 16: mask = 0xffff; break; + case 32: mask = 0xffffffff; break; + default: fprintf(stderr, "inv size in mul %d\n", size); exit(EXIT_FAILURE); + } + + a &= mask; + b &= mask; + return ((int64_t)a * (int64_t) b) & mask; +} + +unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b) +{ + uint64_t res = 0; + unsigned int mask; + + switch (size) { + case 8: mask = 0xff; break; + case 16: mask = 0xffff; break; + case 32: mask = 0xffffffff; break; + default: fprintf(stderr, "inv size in mul %d\n", size); exit(EXIT_FAILURE); + } + + a &= mask; + b &= mask; + res = ((uint64_t)a * (uint64_t)b); + return (res >> 32) & mask; +} + + +unsigned int imul_lo_op_08(char a, char b) +{ + return a*b; +} + +unsigned int imul_lo_op_16(short a, short b) +{ + return a*b; +} + +unsigned int imul_lo_op_32(int a, int b) +{ + return a*b; +} + +int imul_hi_op_08(char a, char b) +{ + int64_t res = 0; + res = a*b; + return (int)(res>>8); +} + +int imul_hi_op_16(short a, short b) +{ + int64_t res = 0; + res = a*b; + return (int)(res>>16); +} + +int imul_hi_op_32(int a, int b) +{ + int64_t res = 0; + res = (int64_t)a*(int64_t)b; + return (int)(res>>32ULL); +} + +unsigned int umul16_lo(unsigned short a, unsigned short b) +{ + return (a*b) & 0xffff; +} + +unsigned int umul16_hi(unsigned short a, unsigned short b) +{ + uint32_t c; + c = a*b; + return (c>>16) & 0xffff; +} + +uint64_t rot_left(uint64_t size, uint64_t a, uint64_t b) +{ + uint64_t tmp; + + b = b & 0x3F; + b %= size; + switch(size){ + case 8: + tmp = (a << b) | ((a & 0xFF) >> (size - b)); + return tmp & 0xFF; + case 16: + tmp = (a << b) | ((a & 0xFFFF) >> (size - b)); + return tmp & 0xFFFF; + case 32: + tmp = (a << b) | ((a & 0xFFFFFFFF) >> (size - b)); + return tmp & 0xFFFFFFFF; + case 64: + tmp = (a << b) | ((a&0xFFFFFFFFFFFFFFFF) >> (size - b)); + return tmp & 0xFFFFFFFFFFFFFFFF; + + /* Support cases for rcl */ + case 9: + tmp = (a << b) | ((a & 0x1FF) >> (size - b)); + return tmp & 0x1FF; + case 17: + tmp = (a << b) | ((a & 0x1FFFF) >> (size - b)); + return tmp & 0x1FFFF; + case 33: + tmp = (a << b) | ((a & 0x1FFFFFFFF) >> (size - b)); + return tmp & 0x1FFFFFFFF; + /* TODO XXX: support rcl in 64 bit mode */ + + default: + fprintf(stderr, "inv size in rotleft %"PRIX64"\n", size); + exit(EXIT_FAILURE); + } +} + +uint64_t rot_right(uint64_t size, uint64_t a, uint64_t b) +{ + uint64_t tmp; + + b = b & 0x3F; + b %= size; + switch(size){ + case 8: + tmp = ((a & 0xFF) >> b) | (a << (size - b)); + return tmp & 0xff; + case 16: + tmp = ((a & 0xFFFF) >> b) | (a << (size - b)); + return tmp & 0xFFFF; + case 32: + tmp = ((a & 0xFFFFFFFF) >> b) | (a << (size - b)); + return tmp & 0xFFFFFFFF; + case 64: + tmp = ((a & 0xFFFFFFFFFFFFFFFF) >> b) | (a << (size - b)); + return tmp & 0xFFFFFFFFFFFFFFFF; + + /* Support cases for rcr */ + case 9: + tmp = ((a & 0x1FF) >> b) | (a << (size - b)); + return tmp & 0x1FF; + case 17: + tmp = ((a & 0x1FFFF) >> b) | (a << (size - b)); + return tmp & 0x1FFFF; + case 33: + tmp = ((a & 0x1FFFFFFFF) >> b) | (a << (size - b)); + return tmp & 0x1FFFFFFFF; + /* TODO XXX: support rcr in 64 bit mode */ + + default: + fprintf(stderr, "inv size in rotright %"PRIX64"\n", size); + exit(EXIT_FAILURE); + } +} + +/* + * Count leading zeros - count the number of zero starting at the most + * significant bit + * + * Example: + * - cntleadzeros(size=32, src=2): 30 + * - cntleadzeros(size=32, src=0): 32 + */ +uint64_t cntleadzeros(uint64_t size, uint64_t src) +{ + int64_t i; + + for (i=(int64_t)size-1; i>=0; i--){ + if (src & (1ull << i)) + return (uint64_t)(size - (i + 1)); + } + return (uint64_t)size; +} + +/* + * Count trailing zeros - count the number of zero starting at the least + * significant bit + * + * Example: + * - cnttrailzeros(size=32, src=2): 1 + * - cnttrailzeros(size=32, src=0): 32 + */ +unsigned int cnttrailzeros(uint64_t size, uint64_t src) +{ + uint64_t i; + for (i=0; i<size; i++){ + if (src & (1ull << i)) + return (unsigned int)i; + } + return (unsigned int)size; +} + + +unsigned int my_imul08(unsigned int a, unsigned int b) +{ + char a08, b08; + short a16; + + a08 = a&0xFF; + b08 = b&0xFF; + a16 = a08*b08; + return (int)a16; +} + + + +unsigned int x86_cpuid(unsigned int a, unsigned int reg_num) +{ + if (reg_num >3){ + fprintf(stderr, "not implemented x86_cpuid reg %x\n", reg_num); + exit(EXIT_FAILURE); + } + // cases are output: EAX: 0; EBX: 1; ECX: 2; EDX: 3 + if (a == 0){ + switch(reg_num){ + case 0: + return 0xa; + // "GenuineIntel" + case 1: + return 0x756E6547; + case 2: + return 0x6C65746E; + case 3: + return 0x49656E69; + } + } + + else if (a == 1){ + switch(reg_num){ + case 0: + // Using a version too high will enable recent + // instruction set + return 0x000006FB; + //return 0x00020652; + case 1: + //return 0x02040800; + return 0x00000800; + case 2: + //return 0x0004E3BD; + return 0x00000209; + case 3: + return (/* fpu */ 1 << 0) | + (/* tsc */ 1 << 4) | + (/* cx8 */ 1 << 8) | + (/* cmov */ 1 << 15) | + (/* mmx */ 1 << 23) | + (/* sse */ 1 << 25) | + (/* sse2 */ 1 << 26) | + (/* ia64 */ 1 << 30); + } + } + // Cache and TLB + else if (a == 2){ + switch(reg_num){ + case 0: + return 0x00000000; + case 1: + return 0x00000000; + case 2: + return 0x00000000; + case 3: + return 0x00000000; + } + } + // Intel thread/core and cache topology + else if (a == 4){ + switch(reg_num){ + case 0: + return 0x00000000; + case 1: + return 0x00000000; + case 2: + return 0x00000000; + case 3: + return 0x00000000; + } + } + // Extended features + else if (a == 7){ + switch(reg_num){ + case 0: + return 0x00000000; + case 1: + return (/* fsgsbase */ 1 << 0) | (/* bmi1 */ 1 << 3); + case 2: + return 0x00000000; + case 3: + return 0x00000000; + } + } + // Extended Function CPUID Information + else if (a == 0x80000000){ + switch(reg_num){ + case 0: + // Pentium 4 Processor supporting Hyper-Threading + // Technology to Intel Xeon Processor 5100 Series + return 0x80000008; + case 1: + return 0x00000000; + case 2: + return 0x00000000; + case 3: + return 0x00000000; + } + } + else if (a == 0x80000001){ + switch(reg_num){ + case 0: + // Extended Processor Signature and Extended Feature + // Bits + return 0x00000000; + case 1: + return 0x00000000; + case 2: + return (/* LAHF-SAHF */ 1 << 0) + | (/* LZCNT */ 0 << 5) + | (/* PREFETCHW */ 1 << 8); + case 3: + return (/* SYSCALL/SYSRET */ 1 << 11) + | (/* Execute Disable Bit available */ 0 << 20) + | (/* 1-GByte pages available */ 0 << 26) + | (/* RDTSCP and IA32_TSC_AUX available */ 0 << 27) + | (/* Intel ® 64 Architecture available */ 1 << 29); + } + } + else{ + fprintf(stderr, "WARNING not implemented x86_cpuid index %X!\n", a); + exit(EXIT_FAILURE); + } + return 0; +} + +//#define DEBUG_MIASM_DOUBLE + +void dump_float(void) +{ + /* + printf("%e\n", vmmngr.float_st0); + printf("%e\n", vmmngr.float_st1); + printf("%e\n", vmmngr.float_st2); + printf("%e\n", vmmngr.float_st3); + printf("%e\n", vmmngr.float_st4); + printf("%e\n", vmmngr.float_st5); + printf("%e\n", vmmngr.float_st6); + printf("%e\n", vmmngr.float_st7); + */ +} + +typedef union { + uint32_t u32; + float flt; +} float_uint32_t; + + +typedef union { + uint64_t u64; + double dbl; +} double_uint64_t; + + +uint32_t fpu_fadd32(uint32_t a, uint32_t b) +{ + float_uint32_t a_cast, b_cast, c_cast; + + a_cast.u32 = a; + b_cast.u32 = b; + + c_cast.flt = a_cast.flt + b_cast.flt; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e + %e -> %e\n", a, b, c_cast.flt); +#endif + return c_cast.u32; +} + +uint64_t fpu_fadd64(uint64_t a, uint64_t b) +{ + double_uint64_t a_cast, b_cast, c_cast; + + a_cast.u64 = a; + b_cast.u64 = b; + + c_cast.dbl = a_cast.dbl + b_cast.dbl; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e + %e -> %e\n", a, b, c_cast.dbl); +#endif + return c_cast.u64; +} + +uint32_t fpu_fsub32(uint32_t a, uint32_t b) +{ + float_uint32_t a_cast, b_cast, c_cast; + + a_cast.u32 = a; + b_cast.u32 = b; + + c_cast.flt = a_cast.flt - b_cast.flt; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e + %e -> %e\n", a, b, c_cast.flt); +#endif + return c_cast.u32; +} + +uint64_t fpu_fsub64(uint64_t a, uint64_t b) +{ + double_uint64_t a_cast, b_cast, c_cast; + + a_cast.u64 = a; + b_cast.u64 = b; + + c_cast.dbl = a_cast.dbl - b_cast.dbl; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e + %e -> %e\n", a, b, c_cast.dbl); +#endif + return c_cast.u64; +} + +uint32_t fpu_fmul32(uint32_t a, uint32_t b) +{ + float_uint32_t a_cast, b_cast, c_cast; + + a_cast.u32 = a; + b_cast.u32 = b; + + c_cast.flt = a_cast.flt * b_cast.flt; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e * %e -> %e\n", a, b, c_cast.flt); +#endif + return c_cast.u32; +} + +uint64_t fpu_fmul64(uint64_t a, uint64_t b) +{ + double_uint64_t a_cast, b_cast, c_cast; + + a_cast.u64 = a; + b_cast.u64 = b; + + c_cast.dbl = a_cast.dbl * b_cast.dbl; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e * %e -> %e\n", a, b, c_cast.dbl); +#endif + return c_cast.u64; +} + +uint32_t fpu_fdiv32(uint32_t a, uint32_t b) +{ + float_uint32_t a_cast, b_cast, c_cast; + + a_cast.u32 = a; + b_cast.u32 = b; + + c_cast.flt = a_cast.flt / b_cast.flt; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e * %e -> %e\n", a, b, c_cast.flt); +#endif + return c_cast.u32; +} + +uint64_t fpu_fdiv64(uint64_t a, uint64_t b) +{ + double_uint64_t a_cast, b_cast, c_cast; + + a_cast.u64 = a; + b_cast.u64 = b; + + c_cast.dbl = a_cast.dbl / b_cast.dbl; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e * %e -> %e\n", a, b, c_cast.dbl); +#endif + return c_cast.u64; +} + +double fpu_ftan(double a) +{ + double b; + b = tan(a); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e tan %e\n", a, b); +#endif + return b; +} + +double fpu_frndint(double a) +{ + int64_t b; + double c; + b = (int64_t)a; + c = (double)b; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e double %e\n", a, c); +#endif + return c; +} + +double fpu_fsin(double a) +{ + double b; + b = sin(a); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e sin %e\n", a, b); +#endif + return b; +} + +double fpu_fcos(double a) +{ + double b; + b = cos(a); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e cos %e\n", a, b); +#endif + return b; +} + + +double fpu_fscale(double a, double b) +{ + double c; + c = a * exp2(trunc(b)); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e *exp2 %e -> %e\n", a, b, c); +#endif + return c; +} + +double fpu_f2xm1(double a) +{ + double b; + b = exp2(a)-1; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e exp2 -1 %e\n", a, b); +#endif + return b; +} + +uint32_t fpu_fsqrt32(uint32_t a) +{ + float_uint32_t a_cast; + a_cast.u32 = a; + a_cast.flt = sqrtf(a_cast.flt); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e sqrt %e\n", a, a_cast.flt); +#endif + return a_cast.u32; +} + +uint64_t fpu_fsqrt64(uint64_t a) +{ + double_uint64_t a_cast; + + a_cast.u64 = a; + a_cast.dbl = sqrt(a_cast.dbl); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e sqrt %e\n", a, a_cast.dbl); +#endif + return a_cast.u64; +} + +uint64_t fpu_fabs64(uint64_t a) +{ + double_uint64_t a_cast; + + a_cast.u64 = a; + a_cast.dbl = fabs(a_cast.dbl); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e abs %e\n", a, a_cast.dbl); +#endif + return a_cast.u64; +} + +uint64_t fpu_fprem64(uint64_t a, uint64_t b) +{ + double_uint64_t a_cast, b_cast, c_cast; + + a_cast.u64 = a; + b_cast.u64 = b; + + c_cast.dbl = fmod(a_cast.dbl, b_cast.dbl); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e %% %e -> %e\n", a, b, c); +#endif + return c_cast.u64; +} + +double fpu_fchs(double a) +{ + double b; + b = -a; +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf(" - %e -> %e\n", a, b); +#endif + return b; +} + +double fpu_fyl2x(double a, double b) +{ + double c; + c = b * (log(a) / log(2)); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("%e * log(%e) -> %e\n", b, a, c); +#endif + return c; +} + +double fpu_fpatan(double a, double b) +{ + double c; + c = atan2(b, a); +#ifdef DEBUG_MIASM_DOUBLE + dump_float(); + printf("arctan(%e / %e) -> %e\n", b, a, c); +#endif + return c; +} + +unsigned int fpu_fcom_c0(double a, double b) +{ + if (isnan(a) || isnan(b)) + return 1; + if (a>=b) + return 0; + return 1; +} +unsigned int fpu_fcom_c1(double a, double b) +{ + //XXX + return 0; +} +unsigned int fpu_fcom_c2(double a, double b) +{ + if (isnan(a) || isnan(b)) + return 1; + return 0; +} +unsigned int fpu_fcom_c3(double a, double b) +{ + if (isnan(a) || isnan(b)) + return 1; + if (a==b) + return 1; + return 0; +} + +uint64_t sint_to_fp_64(int64_t a) +{ + double_uint64_t a_cast; + a_cast.dbl = (double) a; + return a_cast.u64; +} + +uint32_t sint_to_fp_32(int32_t a) +{ + float_uint32_t a_cast; + a_cast.flt = (float) a; + return a_cast.u32; +} + +int32_t fp32_to_sint32(uint32_t a) +{ + // Enforce nearbyint (IEEE-754 behavior) + float rounded; + float_uint32_t a_cast; + a_cast.u32 = a; + rounded = nearbyintf(a_cast.flt); + return (int32_t) rounded; +} + +int64_t fp64_to_sint64(uint64_t a) +{ + // Enforce nearbyint (IEEE-754 behavior) + double rounded; + double_uint64_t a_cast; + a_cast.u64 = a; + rounded = nearbyint(a_cast.dbl); + return (int64_t) rounded; +} + +int32_t fp64_to_sint32(uint64_t a) +{ + // Enforce nearbyint (IEEE-754 behavior) + double rounded; + double_uint64_t a_cast; + a_cast.u64 = a; + rounded = nearbyint(a_cast.dbl); + return (int32_t) rounded; +} + +uint32_t fp64_to_fp32(uint64_t a) +{ + float_uint32_t a_cast32; + double_uint64_t a_cast64; + a_cast64.u64 = a; + a_cast32.flt = (float)a_cast64.dbl; + return a_cast32.u32; +} + +uint64_t fp32_to_fp64(uint32_t a) +{ + float_uint32_t a_cast32; + double_uint64_t a_cast64; + a_cast32.u32 = a; + a_cast64.dbl = (double)a_cast32.flt; + return a_cast64.u64; +} + +uint32_t fpround_towardszero_fp32(uint32_t a) +{ + float_uint32_t a_cast; + a_cast.u32 = a; + a_cast.flt = truncf(a_cast.flt); + return a_cast.u32; +} + +uint64_t fpround_towardszero_fp64(uint64_t a) +{ + double_uint64_t a_cast; + a_cast.u64 = a; + a_cast.dbl = trunc(a_cast.dbl); + return a_cast.u64; +} + + +UDIV(8) +UDIV(16) +UDIV(32) +UDIV(64) + +UMOD(8) +UMOD(16) +UMOD(32) +UMOD(64) + +SDIV(8) +SDIV(16) +SDIV(32) +SDIV(64) + +SMOD(8) +SMOD(16) +SMOD(32) +SMOD(64) diff --git a/src/miasm/jitter/op_semantics.h b/src/miasm/jitter/op_semantics.h new file mode 100644 index 00000000..b76a350c --- /dev/null +++ b/src/miasm/jitter/op_semantics.h @@ -0,0 +1,172 @@ +#ifndef OP_SEMANTICS_H +#define OP_SEMANTICS_H + +#include <stdint.h> + +#if _WIN32 +#define _MIASM_EXPORT __declspec(dllexport) +#define _MIASM_IMPORT __declspec(dllimport) +#else +#define _MIASM_EXPORT +#define _MIASM_IMPORT +#endif + +#define CC_P 1 +#ifdef PARITY_IMPORT +_MIASM_IMPORT extern const uint8_t parity_table[256]; +#else +_MIASM_EXPORT extern const uint8_t parity_table[256]; +#endif +#define parity(a) parity_table[(a) & 0xFF] + + +_MIASM_EXPORT uint16_t bcdadd_16(uint16_t a, uint16_t b); +_MIASM_EXPORT uint16_t bcdadd_cf_16(uint16_t a, uint16_t b); + + +_MIASM_EXPORT unsigned int my_imul08(unsigned int a, unsigned int b); +_MIASM_EXPORT unsigned int mul_lo_op(unsigned int size, unsigned int a, unsigned int b); +_MIASM_EXPORT unsigned int mul_hi_op(unsigned int size, unsigned int a, unsigned int b); +_MIASM_EXPORT unsigned int imul_lo_op_08(char a, char b); +_MIASM_EXPORT unsigned int imul_lo_op_16(short a, short b); +_MIASM_EXPORT unsigned int imul_lo_op_32(int a, int b); +_MIASM_EXPORT int imul_hi_op_08(char a, char b); +_MIASM_EXPORT int imul_hi_op_16(short a, short b); +_MIASM_EXPORT int imul_hi_op_32(int a, int b); + + +_MIASM_EXPORT unsigned int umul16_lo(unsigned short a, unsigned short b); +_MIASM_EXPORT unsigned int umul16_hi(unsigned short a, unsigned short b); + + +_MIASM_EXPORT uint64_t rot_left(uint64_t size, uint64_t a, uint64_t b); +_MIASM_EXPORT uint64_t rot_right(uint64_t size, uint64_t a, uint64_t b); + +_MIASM_EXPORT uint64_t cntleadzeros(uint64_t size, uint64_t src); +_MIASM_EXPORT unsigned int cnttrailzeros(uint64_t size, uint64_t src); + +#define UDIV(sizeA) \ + uint ## sizeA ## _t udiv ## sizeA (uint ## sizeA ## _t a, uint ## sizeA ## _t b) \ + { \ + uint ## sizeA ## _t r; \ + if (b == 0) { \ + fprintf(stderr, "Should not happen\n"); \ + exit(EXIT_FAILURE); \ + } \ + r = a/b; \ + return r; \ + } + + +#define UMOD(sizeA) \ + uint ## sizeA ## _t umod ## sizeA (uint ## sizeA ## _t a, uint ## sizeA ## _t b) \ + { \ + uint ## sizeA ## _t r; \ + if (b == 0) { \ + fprintf(stderr, "Should not happen\n"); \ + exit(EXIT_FAILURE); \ + } \ + r = a%b; \ + return r; \ + } + + +#define SDIV(sizeA) \ + int ## sizeA ## _t sdiv ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ + { \ + int ## sizeA ## _t r; \ + if (b == 0) { \ + fprintf(stderr, "Should not happen\n"); \ + exit(EXIT_FAILURE); \ + } \ + r = a/b; \ + return r; \ + } + + +#define SMOD(sizeA) \ + int ## sizeA ## _t smod ## sizeA (int ## sizeA ## _t a, int ## sizeA ## _t b) \ + { \ + int ## sizeA ## _t r; \ + if (b == 0) { \ + fprintf(stderr, "Should not happen\n"); \ + exit(EXIT_FAILURE); \ + } \ + r = a%b; \ + return r; \ + } + +_MIASM_EXPORT uint64_t udiv64(uint64_t a, uint64_t b); +_MIASM_EXPORT uint64_t umod64(uint64_t a, uint64_t b); +_MIASM_EXPORT int64_t sdiv64(int64_t a, int64_t b); +_MIASM_EXPORT int64_t smod64(int64_t a, int64_t b); + +_MIASM_EXPORT uint32_t udiv32(uint32_t a, uint32_t b); +_MIASM_EXPORT uint32_t umod32(uint32_t a, uint32_t b); +_MIASM_EXPORT int32_t sdiv32(int32_t a, int32_t b); +_MIASM_EXPORT int32_t smod32(int32_t a, int32_t b); + +_MIASM_EXPORT uint16_t udiv16(uint16_t a, uint16_t b); +_MIASM_EXPORT uint16_t umod16(uint16_t a, uint16_t b); +_MIASM_EXPORT int16_t sdiv16(int16_t a, int16_t b); +_MIASM_EXPORT int16_t smod16(int16_t a, int16_t b); + +_MIASM_EXPORT uint8_t udiv8(uint8_t a, uint8_t b); +_MIASM_EXPORT uint8_t umod8(uint8_t a, uint8_t b); +_MIASM_EXPORT int8_t sdiv8(int8_t a, int8_t b); +_MIASM_EXPORT int8_t smod8(int8_t a, int8_t b); + +_MIASM_EXPORT unsigned int x86_cpuid(unsigned int a, unsigned int reg_num); + +_MIASM_EXPORT uint32_t fpu_fadd32(uint32_t a, uint32_t b); +_MIASM_EXPORT uint64_t fpu_fadd64(uint64_t a, uint64_t b); +_MIASM_EXPORT uint32_t fpu_fsub32(uint32_t a, uint32_t b); +_MIASM_EXPORT uint64_t fpu_fsub64(uint64_t a, uint64_t b); +_MIASM_EXPORT uint32_t fpu_fmul32(uint32_t a, uint32_t b); +_MIASM_EXPORT uint64_t fpu_fmul64(uint64_t a, uint64_t b); +_MIASM_EXPORT uint32_t fpu_fdiv32(uint32_t a, uint32_t b); +_MIASM_EXPORT uint64_t fpu_fdiv64(uint64_t a, uint64_t b); +_MIASM_EXPORT double fpu_ftan(double a); +_MIASM_EXPORT double fpu_frndint(double a); +_MIASM_EXPORT double fpu_fsin(double a); +_MIASM_EXPORT double fpu_fcos(double a); +_MIASM_EXPORT double fpu_fscale(double a, double b); +_MIASM_EXPORT double fpu_f2xm1(double a); +_MIASM_EXPORT uint32_t fpu_fsqrt32(uint32_t a); +_MIASM_EXPORT uint64_t fpu_fsqrt64(uint64_t a); +_MIASM_EXPORT uint64_t fpu_fabs64(uint64_t a); +_MIASM_EXPORT uint64_t fpu_fprem64(uint64_t a, uint64_t b); +_MIASM_EXPORT double fpu_fchs(double a); +_MIASM_EXPORT double fpu_fyl2x(double a, double b); +_MIASM_EXPORT double fpu_fpatan(double a, double b); +_MIASM_EXPORT unsigned int fpu_fcom_c0(double a, double b); +_MIASM_EXPORT unsigned int fpu_fcom_c1(double a, double b); +_MIASM_EXPORT unsigned int fpu_fcom_c2(double a, double b); +_MIASM_EXPORT unsigned int fpu_fcom_c3(double a, double b); + +_MIASM_EXPORT uint64_t sint_to_fp_64(int64_t a); +_MIASM_EXPORT uint32_t sint_to_fp_32(int32_t a); +_MIASM_EXPORT int32_t fp32_to_sint32(uint32_t a); +_MIASM_EXPORT int64_t fp64_to_sint64(uint64_t a); +_MIASM_EXPORT int32_t fp64_to_sint32(uint64_t a); +_MIASM_EXPORT uint32_t fp64_to_fp32(uint64_t a); +_MIASM_EXPORT uint64_t fp32_to_fp64(uint32_t a); +_MIASM_EXPORT uint32_t fpround_towardszero_fp32(uint32_t a); +_MIASM_EXPORT uint64_t fpround_towardszero_fp64(uint64_t a); + +#define SHIFT_RIGHT_ARITH(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + (((int ## size ## _t) (value)) < 0 ? -1 : 0) : \ + (((int ## size ## _t) (value)) >> (shift)))) + +#define SHIFT_RIGHT_LOGIC(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + 0 : \ + (((uint ## size ## _t) (value)) >> (shift)))) + +#define SHIFT_LEFT_LOGIC(size, value, shift) \ + ((uint ## size ## _t)((((uint64_t) (shift)) > ((size) - 1))? \ + 0 : \ + (((uint ## size ## _t) (value)) << (shift)))) + +#endif diff --git a/src/miasm/jitter/queue.h b/src/miasm/jitter/queue.h new file mode 100644 index 00000000..0caf72fb --- /dev/null +++ b/src/miasm/jitter/queue.h @@ -0,0 +1,553 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +//#include <sys/cdefs.h> + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !(__GNUC__ || __INTEL_COMPILER) */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/src/miasm/jitter/vm_mngr.c b/src/miasm/jitter/vm_mngr.c new file mode 100644 index 00000000..9fe8ab65 --- /dev/null +++ b/src/miasm/jitter/vm_mngr.c @@ -0,0 +1,1032 @@ +/* +** 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. +*/ +#include "vm_mngr.h" + +#include <inttypes.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "queue.h" + + + +/****************memory manager**************/ + + + + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +// #define DEBUG_MIASM_AUTOMOD_CODE +#define MEMORY_ACCESS_LIST_INITIAL_COUNT 100 + +/* + To avoid alloc/free for each instruction access, the buffer is allocated here, + and is increased depending of program needs. + */ +void memory_access_list_init(struct memory_access_list * access) +{ + access->array = malloc(MEMORY_ACCESS_LIST_INITIAL_COUNT * sizeof(struct memory_access)); + if (access->array == NULL) { + fprintf(stderr, "cannot realloc struct memory_access access->array\n"); + exit(EXIT_FAILURE); + } + access->allocated = MEMORY_ACCESS_LIST_INITIAL_COUNT; + access->num = 0; +} + +void memory_access_list_reset(struct memory_access_list * access) +{ + access->num = 0; +} + +void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop) +{ + if (access->num >= access->allocated) { + if (access->allocated == 0) + access->allocated = 1; + else { + if (access->allocated >= SIZE_MAX / 2) { + fprintf(stderr, "Cannot alloc more pages\n"); + exit(EXIT_FAILURE); + } + access->allocated *= 2; + } + access->array = realloc(access->array, access->allocated * sizeof(struct memory_access)); + if (access->array == NULL) { + fprintf(stderr, "cannot realloc struct memory_access access->array\n"); + exit(EXIT_FAILURE); + } + } + access->array[access->num].start = start; + access->array[access->num].stop = stop; + access->num += 1; +} + + + +uint16_t set_endian16(vm_mngr_t* vm_mngr, uint16_t val) +{ + if (vm_mngr->sex == __BYTE_ORDER) + return val; + else + return Endian16_Swap(val); +} + +uint32_t set_endian32(vm_mngr_t* vm_mngr, uint32_t val) +{ + if (vm_mngr->sex == __BYTE_ORDER) + return val; + else + return Endian32_Swap(val); +} + +uint64_t set_endian64(vm_mngr_t* vm_mngr, uint64_t val) +{ + if (vm_mngr->sex == __BYTE_ORDER) + return val; + else + return Endian64_Swap(val); +} + +void print_val(uint64_t base, uint64_t addr) +{ + uint64_t *ptr = (uint64_t *) (intptr_t) addr; + fprintf(stderr, "addr 0x%"PRIX64" val 0x%"PRIX64"\n", addr-base, *ptr); +} + +int midpoint(int imin, int imax) +{ + return (imin + imax) / 2; +} + + +int find_page_node(struct memory_page_node * array, uint64_t key, int imin, int imax) +{ + // continue searching while [imin,imax] is not empty + while (imin <= imax) { + // calculate the midpoint for roughly equal partition + int imid = midpoint(imin, imax); + if(array[imid].ad <= key && key < array[imid].ad + array[imid].size) + // key found at index imid + return imid; + // determine which subarray to search + else if (array[imid].ad < key) + // change min index to search upper subarray + imin = imid + 1; + else + // change max index to search lower subarray + imax = imid - 1; + } + // key was not found + return -1; +} + +struct memory_page_node * get_memory_page_from_address(vm_mngr_t* vm_mngr, uint64_t ad, int raise_exception) +{ + struct memory_page_node * mpn; + int i; + + i = find_page_node(vm_mngr->memory_pages_array, + ad, + 0, + vm_mngr->memory_pages_number - 1); + if (i >= 0) { + mpn = &vm_mngr->memory_pages_array[i]; + if ((mpn->ad <= ad) && (ad < mpn->ad + mpn->size)) + return mpn; + } + if (raise_exception) { + fprintf(stderr, "WARNING: address 0x%"PRIX64" is not mapped in virtual memory:\n", ad); + vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL; + } + return NULL; +} + +static uint64_t memory_page_read(vm_mngr_t* vm_mngr, unsigned int my_size, uint64_t ad) +{ + struct memory_page_node * mpn; + unsigned char * addr; + uint64_t ret = 0; + struct memory_breakpoint_info * b; + + + mpn = get_memory_page_from_address(vm_mngr, ad, 1); + if (!mpn) + return 0; + + if ((mpn->access & PAGE_READ) == 0){ + fprintf(stderr, "access to non readable page!! %"PRIX64"\n", ad); + vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL; + return 0; + } + + /* check read breakpoint */ + LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){ + if ((b->access & BREAKPOINT_READ) == 0) + continue; + if ((b->ad <= ad) && (ad < b->ad + b->size)) + vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY; + } + + + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + + /* read fits in a page */ + if (ad - mpn->ad + my_size/8 <= mpn->size){ + switch(my_size){ + case 8: + ret = *((unsigned char*)addr)&0xFF; + break; + case 16: + ret = *((unsigned short*)addr)&0xFFFF; + ret = set_endian16(vm_mngr, (uint16_t)ret); + break; + case 32: + ret = *((unsigned int*)addr)&0xFFFFFFFF; + ret = set_endian32(vm_mngr, (uint32_t)ret); + break; + case 64: + ret = *((uint64_t*)addr)&0xFFFFFFFFFFFFFFFFULL; + ret = set_endian64(vm_mngr, ret); + break; + default: + fprintf(stderr, "Bad memory access size %d\n", my_size); + exit(EXIT_FAILURE); + break; + } + } + /* read is multiple page wide */ + else{ + unsigned int new_size = my_size; + int index = 0; + while (new_size){ + mpn = get_memory_page_from_address(vm_mngr, ad, 1); + if (!mpn) + return 0; + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + ret |= ((uint64_t)(*((unsigned char*)addr)&0xFF))<<(index); + index +=8; + new_size -= 8; + ad ++; + } + switch(my_size){ + case 8: + break; + case 16: + ret = set_endian16(vm_mngr, (uint16_t)ret); + break; + case 32: + ret = set_endian32(vm_mngr, (uint32_t)ret); + break; + case 64: + ret = set_endian64(vm_mngr, ret); + break; + default: + fprintf(stderr, "Bad memory access size %d\n", my_size); + exit(EXIT_FAILURE); + break; + } + } + return ret; +} + +static void memory_page_write(vm_mngr_t* vm_mngr, unsigned int my_size, + uint64_t ad, uint64_t src) +{ + struct memory_page_node * mpn; + unsigned char * addr; + struct memory_breakpoint_info * b; + + mpn = get_memory_page_from_address(vm_mngr, ad, 1); + if (!mpn) + return; + + if ((mpn->access & PAGE_WRITE) == 0){ + fprintf(stderr, "access to non writable page!! %"PRIX64"\n", ad); + vm_mngr->exception_flags |= EXCEPT_ACCESS_VIOL; + return ; + } + + /* check read breakpoint*/ + LIST_FOREACH(b, &vm_mngr->memory_breakpoint_pool, next){ + if ((b->access & BREAKPOINT_WRITE) == 0) + continue; + if ((b->ad <= ad) && (ad < b->ad + b->size)) + vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY; + } + + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + + /* write fits in a page */ + if (ad - mpn->ad + my_size/8 <= mpn->size){ + switch(my_size){ + case 8: + *((unsigned char*)addr) = src&0xFF; + break; + case 16: + src = set_endian16(vm_mngr, (uint16_t)src); + *((unsigned short*)addr) = src&0xFFFF; + break; + case 32: + src = set_endian32(vm_mngr, (uint32_t)src); + *((unsigned int*)addr) = src&0xFFFFFFFF; + break; + case 64: + src = set_endian64(vm_mngr, src); + *((uint64_t*)addr) = src&0xFFFFFFFFFFFFFFFFULL; + break; + default: + fprintf(stderr, "Bad memory access size %d\n", my_size); + exit(EXIT_FAILURE); + break; + } + } + /* write is multiple page wide */ + else{ + switch(my_size){ + + case 8: + break; + case 16: + src = set_endian16(vm_mngr, (uint16_t)src); + break; + case 32: + src = set_endian32(vm_mngr, (uint32_t)src); + break; + case 64: + src = set_endian64(vm_mngr, src); + break; + default: + fprintf(stderr, "Bad memory access size %d\n", my_size); + exit(EXIT_FAILURE); + break; + } + while (my_size){ + mpn = get_memory_page_from_address(vm_mngr, ad, 1); + if (!mpn) + return; + + addr = &((unsigned char*)mpn->ad_hp)[ad - mpn->ad]; + *((unsigned char*)addr) = src&0xFF; + my_size -= 8; + src >>=8; + ad ++; + } + } +} + +// ################## + +void dump_code_bloc(vm_mngr_t* vm_mngr) +{ + struct code_bloc_node * cbp; + LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){ + fprintf(stderr, "%"PRIX64"%"PRIX64"\n", cbp->ad_start, cbp->ad_stop); + } + +} + +void add_range_to_list(struct memory_access_list * access, uint64_t addr1, uint64_t addr2) +{ + if (access->num > 0) { + /* Check match on upper bound */ + if (access->array[access->num-1].stop == addr1) { + access->array[access->num-1].stop = addr2; + return; + } + + /* Check match on lower bound */ + if (access->array[0].start == addr2) { + access->array[0].start = addr1; + return; + } + } + + /* No merge, add to the list */ + memory_access_list_add(access, addr1, addr2); +} + + +void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size) +{ + add_range_to_list(&(vm_mngr->memory_r), addr, addr + size); +} + +void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size) +{ + add_range_to_list(&(vm_mngr->memory_w), addr, addr + size); +} + +void check_invalid_code_blocs(vm_mngr_t* vm_mngr) +{ + size_t i; + struct code_bloc_node * cbp; + for (i=0;i<vm_mngr->memory_w.num; i++) { + if (vm_mngr->exception_flags & EXCEPT_CODE_AUTOMOD) + break; + if (vm_mngr->memory_w.array[i].stop <= vm_mngr->code_bloc_pool_ad_min || + vm_mngr->memory_w.array[i].start >=vm_mngr->code_bloc_pool_ad_max) + continue; + + LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){ + if ((cbp->ad_start < vm_mngr->memory_w.array[i].stop) && + (vm_mngr->memory_w.array[i].start < cbp->ad_stop)){ +#ifdef DEBUG_MIASM_AUTOMOD_CODE + fprintf(stderr, "**********************************\n"); + fprintf(stderr, "self modifying code %"PRIX64" %"PRIX64"\n", + vm_mngr->memory_w.array[i].start, + vm_mngr->memory_w.array[i].stop); + fprintf(stderr, "**********************************\n"); +#endif + vm_mngr->exception_flags |= EXCEPT_CODE_AUTOMOD; + break; + } + } + } +} + + +void check_memory_breakpoint(vm_mngr_t* vm_mngr) +{ + size_t i; + struct memory_breakpoint_info * memory_bp; + + /* Check memory breakpoints */ + LIST_FOREACH(memory_bp, &vm_mngr->memory_breakpoint_pool, next) { + if (vm_mngr->exception_flags & EXCEPT_BREAKPOINT_MEMORY) + break; + if (memory_bp->access & BREAKPOINT_READ) { + for (i=0;i<vm_mngr->memory_r.num; i++) { + if ((memory_bp->ad < vm_mngr->memory_r.array[i].stop) && + (vm_mngr->memory_r.array[i].start < memory_bp->ad + memory_bp->size)) { + vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY; + break; + } + } + } + if (memory_bp->access & BREAKPOINT_WRITE) { + for (i=0;i<vm_mngr->memory_w.num; i++) { + if ((memory_bp->ad < vm_mngr->memory_w.array[i].stop) && + (vm_mngr->memory_w.array[i].start < memory_bp->ad + memory_bp->size)) { + vm_mngr->exception_flags |= EXCEPT_BREAKPOINT_MEMORY; + break; + } + } + } + } +} + + +PyObject* get_memory_pylist(vm_mngr_t* vm_mngr, struct memory_access_list* memory_list) +{ + size_t i; + PyObject *pylist; + PyObject *range; + + pylist = PyList_New(memory_list->num); + for (i=0;i<memory_list->num;i++) { + range = PyTuple_New(2); + PyTuple_SetItem(range, 0, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].start)); + PyTuple_SetItem(range, 1, PyLong_FromUnsignedLongLong((uint64_t)memory_list->array[i].stop)); + PyList_SetItem(pylist, i, range); + } + return pylist; + +} + +PyObject* get_memory_read(vm_mngr_t* vm_mngr) +{ + return get_memory_pylist(vm_mngr, &vm_mngr->memory_r); +} + +PyObject* get_memory_write(vm_mngr_t* vm_mngr) +{ + return get_memory_pylist(vm_mngr, &vm_mngr->memory_w); +} + +void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src) +{ + add_mem_write(vm_mngr, addr, 1); + memory_page_write(vm_mngr, 8, addr, src); +} + +void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src) +{ + add_mem_write(vm_mngr, addr, 2); + memory_page_write(vm_mngr, 16, addr, src); +} +void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src) +{ + add_mem_write(vm_mngr, addr, 4); + memory_page_write(vm_mngr, 32, addr, src); +} +void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src) +{ + add_mem_write(vm_mngr, addr, 8); + memory_page_write(vm_mngr, 64, addr, src); +} + +unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr) +{ + unsigned char ret; + add_mem_read(vm_mngr, addr, 1); + ret = (unsigned char)memory_page_read(vm_mngr, 8, addr); + return ret; +} +unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr) +{ + unsigned short ret; + add_mem_read(vm_mngr, addr, 2); + ret = (unsigned short)memory_page_read(vm_mngr, 16, addr); + return ret; +} +unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr) +{ + unsigned int ret; + add_mem_read(vm_mngr, addr, 4); + ret = (unsigned int)memory_page_read(vm_mngr, 32, addr); + return ret; +} +uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr) +{ + uint64_t ret; + add_mem_read(vm_mngr, addr, 8); + ret = memory_page_read(vm_mngr, 64, addr); + return ret; +} + + +int vm_read_mem(vm_mngr_t* vm_mngr, uint64_t addr, char** buffer_ptr, size_t size) +{ + char* buffer; + size_t len; + uint64_t addr_diff; + size_t addr_diff_st; + struct memory_page_node * mpn; + + buffer = malloc(size); + *buffer_ptr = buffer; + if (!buffer){ + fprintf(stderr, "Error: cannot alloc read\n"); + exit(EXIT_FAILURE); + } + + /* read is multiple page wide */ + while (size){ + mpn = get_memory_page_from_address(vm_mngr, addr, 1); + if (!mpn){ + free(*buffer_ptr); + PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address"); + return -1; + } + + addr_diff = addr - mpn->ad; + if (addr_diff > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + addr_diff_st = (size_t) addr_diff; + len = MIN(size, mpn->size - addr_diff_st); + memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len); + buffer += len; + addr += len; + size -= len; + } + + return 0; +} + + +/* + Try to read @size bytes from vm mmemory + Return the number of bytes consecutively read +*/ +uint64_t vm_read_mem_ret_buf(vm_mngr_t* vm_mngr, uint64_t addr, size_t size, char *buffer) +{ + size_t len; + uint64_t addr_diff; + uint64_t size_out; + size_t addr_diff_st; + + struct memory_page_node * mpn; + + size_out = 0; + /* read is multiple page wide */ + while (size){ + mpn = get_memory_page_from_address(vm_mngr, addr, 0); + if (!mpn){ + return size_out; + } + + addr_diff = addr - mpn->ad; + if (addr_diff > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + addr_diff_st = (size_t) addr_diff; + len = MIN(size, mpn->size - addr_diff_st); + memcpy(buffer, (char*)mpn->ad_hp + (addr_diff_st), len); + buffer += len; + size_out += len; + addr += len; + size -= len; + } + + return size_out; +} + + +int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, size_t size) +{ + size_t len; + uint64_t addr_diff; + size_t addr_diff_st; + struct memory_page_node * mpn; + + if (size > SIZE_MAX) { + fprintf(stderr, "Write size wider than supported system\n"); + exit(EXIT_FAILURE); + } + + /* write is multiple page wide */ + while (size){ + mpn = get_memory_page_from_address(vm_mngr, addr, 1); + if (!mpn){ + PyErr_SetString(PyExc_RuntimeError, "Error: cannot find address"); + return -1; + } + + addr_diff = addr - mpn->ad; + if (addr_diff > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + addr_diff_st = (size_t) addr_diff; + len = MIN(size, mpn->size - addr_diff_st); + memcpy((char*)mpn->ad_hp + addr_diff_st, buffer, len); + buffer += len; + addr += len; + size -= len; + } + + return 0; +} + + + +int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, size_t size) +{ + size_t len; + uint64_t addr_diff; + size_t addr_diff_st; + struct memory_page_node * mpn; + + if (size > SIZE_MAX) { + fprintf(stderr, "Test size wider than supported system\n"); + exit(EXIT_FAILURE); + } + + /* test multiple page wide */ + while (size){ + mpn = get_memory_page_from_address(vm_mngr, addr, 0); + if (!mpn) + return 0; + + addr_diff = addr - mpn->ad; + if (addr_diff > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + addr_diff_st = (size_t) addr_diff; + len = MIN(size, mpn->size - addr_diff_st); + addr += len; + size -= len; + } + + return 1; +} + +struct memory_page_node * create_memory_page_node(uint64_t ad, size_t size, unsigned int access, const char *name) +{ + struct memory_page_node * mpn; + void* ad_hp; + + mpn = malloc(sizeof(*mpn)); + if (!mpn){ + fprintf(stderr, "Error: cannot alloc mpn\n"); + return NULL; + } + ad_hp = malloc(size); + if (!ad_hp){ + free(mpn); + fprintf(stderr, "Error: cannot alloc %zu\n", size); + return NULL; + } + mpn->name = malloc(strlen(name) + 1); + if (!mpn->name){ + free(mpn); + free(ad_hp); + fprintf(stderr, "Error: cannot alloc\n"); + return NULL; + } + + mpn->ad = ad; + mpn->size = size; + mpn->access = access; + mpn->ad_hp = ad_hp; + strcpy(mpn->name, name); + + return mpn; +} + + +struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop) +{ + struct code_bloc_node * cbp; + + cbp = malloc(sizeof(*cbp)); + if (!cbp){ + fprintf(stderr, "Error: cannot alloc cbp\n"); + exit(EXIT_FAILURE); + } + + cbp->ad_start = ad_start; + cbp->ad_stop = ad_stop; + + return cbp; +} + + +void add_code_bloc(vm_mngr_t* vm_mngr, struct code_bloc_node* cbp) +{ + LIST_INSERT_HEAD(&vm_mngr->code_bloc_pool, cbp, next); + if (vm_mngr->code_bloc_pool_ad_min> cbp->ad_start) + vm_mngr->code_bloc_pool_ad_min = cbp->ad_start; + if (vm_mngr->code_bloc_pool_ad_max< cbp->ad_stop) + vm_mngr->code_bloc_pool_ad_max = cbp->ad_stop; +} + +void dump_code_bloc_pool(vm_mngr_t* vm_mngr) +{ + struct code_bloc_node * cbp; + + LIST_FOREACH(cbp, &vm_mngr->code_bloc_pool, next){ + printf("ad start %"PRIX64" ad_stop %"PRIX64"\n", + cbp->ad_start, + cbp->ad_stop); + } +} + + +void init_memory_page_pool(vm_mngr_t* vm_mngr) +{ + + vm_mngr->memory_pages_number = 0; + vm_mngr->memory_pages_array = NULL; +} + +void init_code_bloc_pool(vm_mngr_t* vm_mngr) +{ + LIST_INIT(&vm_mngr->code_bloc_pool); + vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL; + vm_mngr->code_bloc_pool_ad_max = 0; + + memory_access_list_init(&(vm_mngr->memory_r)); + memory_access_list_init(&(vm_mngr->memory_w)); + + +} + +void init_memory_breakpoint(vm_mngr_t* vm_mngr) +{ + LIST_INIT(&vm_mngr->memory_breakpoint_pool); +} + + +void reset_memory_page_pool(vm_mngr_t* vm_mngr) +{ + struct memory_page_node * mpn; + int i; + for (i=0;i<vm_mngr->memory_pages_number; i++) { + mpn = &vm_mngr->memory_pages_array[i]; + free(mpn->ad_hp); + free(mpn->name); + } + free(vm_mngr->memory_pages_array); + vm_mngr->memory_pages_array = NULL; + vm_mngr->memory_pages_number = 0; +} + + +void reset_code_bloc_pool(vm_mngr_t* vm_mngr) +{ + struct code_bloc_node * cbp; + + + while (!LIST_EMPTY(&vm_mngr->code_bloc_pool)) { + cbp = LIST_FIRST(&vm_mngr->code_bloc_pool); + LIST_REMOVE(cbp, next); + free(cbp); + } + vm_mngr->code_bloc_pool_ad_min = 0xffffffffffffffffULL; + vm_mngr->code_bloc_pool_ad_max = 0; +} + +void reset_memory_access(vm_mngr_t* vm_mngr) +{ + memory_access_list_reset(&(vm_mngr->memory_r)); + memory_access_list_reset(&(vm_mngr->memory_w)); +} + +void reset_memory_breakpoint(vm_mngr_t* vm_mngr) +{ + struct memory_breakpoint_info * mpn; + + while (!LIST_EMPTY(&vm_mngr->memory_breakpoint_pool)) { + mpn = LIST_FIRST(&vm_mngr->memory_breakpoint_pool); + LIST_REMOVE(mpn, next); + free(mpn); + } + +} + + + +/* We don't use dichotomy here for the insertion */ +int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a) +{ + struct memory_page_node * mpn; + int i; + + for (i=0;i<vm_mngr->memory_pages_number; i++) { + mpn = &vm_mngr->memory_pages_array[i]; + if (mpn->ad >= mpn_a->ad + mpn_a->size) + continue; + if (mpn->ad + mpn->size <= mpn_a->ad) + continue; + fprintf(stderr, + "Error: attempt to add page (0x%"PRIX64" 0x%"PRIX64") " + "overlapping page (0x%"PRIX64" 0x%"PRIX64")\n", + mpn_a->ad, mpn_a->ad + mpn_a->size, + mpn->ad, mpn->ad + mpn->size); + + return 1; + } + + return 0; +} + + +/* We don't use dichotomy here for the insertion */ +void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a) +{ + struct memory_page_node * mpn; + int i; + + for (i=0; i < vm_mngr->memory_pages_number; i++) { + mpn = &vm_mngr->memory_pages_array[i]; + if (mpn->ad < mpn_a->ad) + continue; + break; + } + vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array, + sizeof(struct memory_page_node) * + (vm_mngr->memory_pages_number+1)); + if (vm_mngr->memory_pages_array == NULL) { + fprintf(stderr, "cannot realloc struct memory_page_node vm_mngr->memory_pages_array\n"); + exit(EXIT_FAILURE); + } + + + memmove(&vm_mngr->memory_pages_array[i+1], + &vm_mngr->memory_pages_array[i], + sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i) + ); + + vm_mngr->memory_pages_array[i] = *mpn_a; + vm_mngr->memory_pages_number ++; +} + +void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad) +{ + struct memory_page_node * mpn; + int i; + + i = find_page_node(vm_mngr->memory_pages_array, + ad, + 0, + vm_mngr->memory_pages_number - 1); + if (i < 0) { + return; + } + + mpn = &vm_mngr->memory_pages_array[i]; + free(mpn->name); + free(mpn->ad_hp); + memmove(&vm_mngr->memory_pages_array[i], + &vm_mngr->memory_pages_array[i+1], + sizeof(struct memory_page_node) * (vm_mngr->memory_pages_number - i - 1) + ); + vm_mngr->memory_pages_number --; + vm_mngr->memory_pages_array = realloc(vm_mngr->memory_pages_array, + sizeof(struct memory_page_node) * + (vm_mngr->memory_pages_number)); +} + +/* Return a char* representing the repr of vm_mngr_t object */ +char* dump(vm_mngr_t* vm_mngr) +{ + char buf[0x100]; + int length; + char *buf_final; + int i; + char buf_addr[0x20]; + char buf_size[0x20]; + struct memory_page_node * mpn; + /* 0x1234567812345678 0x1234567812345678 */ + char* intro = "Addr Size Access Comment\n"; + size_t total_len = strlen(intro) + 1; + + buf_final = malloc(total_len); + if (buf_final == NULL) { + fprintf(stderr, "Error: cannot alloc char* buf_final\n"); + exit(EXIT_FAILURE); + } + strcpy(buf_final, intro); + for (i=0; i< vm_mngr->memory_pages_number; i++) { + mpn = &vm_mngr->memory_pages_array[i]; + snprintf(buf_addr, sizeof(buf_addr), + "0x%"PRIX64, (uint64_t)mpn->ad); + snprintf(buf_size, sizeof(buf_size), + "0x%"PRIX64, (uint64_t)mpn->size); + + length = snprintf(buf, sizeof(buf) - 1, + "%-18s %-18s %c%c%c %s", + buf_addr, + buf_size, + mpn->access & PAGE_READ? 'R':'_', + mpn->access & PAGE_WRITE? 'W':'_', + mpn->access & PAGE_EXEC? 'X':'_', + mpn->name + ); + strcat(buf, "\n"); + total_len += length + 1 + 1; + buf_final = realloc(buf_final, total_len); + if (buf_final == NULL) { + fprintf(stderr, "cannot realloc char* buf_final\n"); + exit(EXIT_FAILURE); + } + strcat(buf_final, buf); + } + + return buf_final; +} + +void dump_memory_breakpoint_pool(vm_mngr_t* vm_mngr) +{ + struct memory_breakpoint_info * mpn; + + LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){ + printf("ad %"PRIX64" size %"PRIX64" access %"PRIX64"\n", + mpn->ad, + mpn->size, + mpn->access + ); + } +} + + +void add_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, uint64_t size, unsigned int access) +{ + struct memory_breakpoint_info * mpn_a; + mpn_a = malloc(sizeof(*mpn_a)); + if (!mpn_a) { + fprintf(stderr, "Error: cannot alloc\n"); + exit(EXIT_FAILURE); + } + mpn_a->ad = ad; + mpn_a->size = size; + mpn_a->access = access; + + LIST_INSERT_HEAD(&vm_mngr->memory_breakpoint_pool, mpn_a, next); + +} + +void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int access) +{ + struct memory_breakpoint_info * mpn; + + LIST_FOREACH(mpn, &vm_mngr->memory_breakpoint_pool, next){ + if (mpn->ad == ad && mpn->access == access) + LIST_REMOVE(mpn, next); + } + +} + + +/********************************************/ + +void hexdump(char* m, unsigned int l) +{ + unsigned int i, j, last; + last = 0; + for (i=0;i<l;i++){ + if (!(i%0x10) && i){ + last = i; + printf(" "); + for (j=-0x10;j<0;j++){ + if (isprint(m[i+j])){ + printf("%c", m[i+j]); + } + else{ + printf("."); + } + } + printf("\n"); + } + printf("%.2X ", m[i]&0xFF); + } + l-=last; + if (l){ + for (j=i;j<last+0x10;j++) + printf(" "); + printf(" "); + for (j = 0;l;j++){ + if (isprint(m[last+j])){ + printf("%c", m[last+j]); + } + else{ + printf("."); + } + l--; + } + } + printf("\n"); + +} + + +// Return vm_mngr's exception flag value +_MIASM_EXPORT uint64_t get_exception_flag(vm_mngr_t* vm_mngr) +{ + return vm_mngr->exception_flags; +} diff --git a/src/miasm/jitter/vm_mngr.h b/src/miasm/jitter/vm_mngr.h new file mode 100644 index 00000000..f7aea5b8 --- /dev/null +++ b/src/miasm/jitter/vm_mngr.h @@ -0,0 +1,311 @@ +/* +** 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. +*/ +#ifndef CODENAT_H +#define CODENAT_H + +#if defined(_WIN32) || defined(_WIN64) +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif + +#if _WIN32 +#define _MIASM_EXPORT __declspec(dllexport) +#else +#define _MIASM_EXPORT +#endif + +#include <Python.h> +#include <stdint.h> + +#include "queue.h" + +#ifdef __APPLE__ +#define __BYTE_ORDER __BYTE_ORDER__ +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +#define __BYTE_ORDER _BYTE_ORDER +#define __BIG_ENDIAN _BIG_ENDIAN +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#elif defined(_WIN32) || defined(_WIN64) +#define __BYTE_ORDER __LITTLE_ENDIAN +#define __BIG_ENDIAN '>' +#define __LITTLE_ENDIAN '<' +#elif defined(__ANDROID__) +#define __BYTE_ORDER __BYTE_ORDER__ +#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ +#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ +#endif + + +#define Endian16_Swap(value) \ + ((((uint16_t)((value) & 0x00FF)) << 8) | \ + (((uint16_t)((value) & 0xFF00)) >> 8)) + +#define Endian32_Swap(value) \ + ((((uint32_t)((value) & 0x000000FF)) << 24) | \ + (((uint32_t)((value) & 0x0000FF00)) << 8) | \ + (((uint32_t)((value) & 0x00FF0000)) >> 8) | \ + (((uint32_t)((value) & 0xFF000000)) >> 24)) + +#define Endian64_Swap(value) \ + (((((uint64_t)value)<<56) & 0xFF00000000000000ULL) | \ + ((((uint64_t)value)<<40) & 0x00FF000000000000ULL) | \ + ((((uint64_t)value)<<24) & 0x0000FF0000000000ULL) | \ + ((((uint64_t)value)<< 8) & 0x000000FF00000000ULL) | \ + ((((uint64_t)value)>> 8) & 0x00000000FF000000ULL) | \ + ((((uint64_t)value)>>24) & 0x0000000000FF0000ULL) | \ + ((((uint64_t)value)>>40) & 0x000000000000FF00ULL) | \ + ((((uint64_t)value)>>56) & 0x00000000000000FFULL)) + + +LIST_HEAD(code_bloc_list_head, code_bloc_node); +LIST_HEAD(memory_breakpoint_info_head, memory_breakpoint_info); + + +#define BREAKPOINT_READ 1 +#define BREAKPOINT_WRITE 2 + +#define BREAK_SIGALARM 1<<5 + +#define MAX_MEMORY_PAGE_POOL_TAB 0x100000 +#define MEMORY_PAGE_POOL_MASK_BIT 12 +#define VM_BIG_ENDIAN 1 +#define VM_LITTLE_ENDIAN 2 + + +struct memory_page_node { + uint64_t ad; + size_t size; + uint64_t access; + void* ad_hp; + char* name; +}; + +struct memory_access { + uint64_t start; + uint64_t stop; +}; + +struct memory_access_list { + struct memory_access *array; + size_t allocated; + size_t num; +}; + +typedef struct { + int sex; + struct code_bloc_list_head code_bloc_pool; + struct memory_breakpoint_info_head memory_breakpoint_pool; + + int memory_pages_number; + struct memory_page_node* memory_pages_array; + + uint64_t code_bloc_pool_ad_min; + uint64_t code_bloc_pool_ad_max; + + uint64_t exception_flags; + uint64_t exception_flags_new; + PyObject *addr2obj; + + + struct memory_access_list memory_r; + struct memory_access_list memory_w; + + + int write_num; + +}vm_mngr_t; + + + +typedef struct { + PyObject *func; +}func_resolver; + + + + +//extern vm_mngr_t vmmngr; + +struct code_bloc_node { + uint64_t ad_start; + uint64_t ad_stop; + uint64_t ad_code; + LIST_ENTRY(code_bloc_node) next; +}; + + +struct memory_breakpoint_info { + uint64_t ad; + uint64_t size; + uint64_t access; + LIST_ENTRY(memory_breakpoint_info) next; +}; + + + +#define PAGE_READ 1 +#define PAGE_WRITE 2 +#define PAGE_EXEC 4 + +#define EXCEPT_DO_NOT_UPDATE_PC (1<<25) + +// interrupt with eip update after instr +#define EXCEPT_CODE_AUTOMOD (1<<0) +#define EXCEPT_SOFT_BP (1<<1) +#define EXCEPT_INT_XX (1<<2) + +#define EXCEPT_BREAKPOINT_MEMORY (1<<10) +// Deprecated +#define EXCEPT_BREAKPOINT_INTERN (EXCEPT_BREAKPOINT_MEMORY) + +#define EXCEPT_NUM_UPDT_EIP (1<<11) +// interrupt with eip at instr +#define EXCEPT_UNK_MEM_AD ((1<<12) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_THROW_SEH ((1<<13) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_UNK_EIP ((1<<14) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_ACCESS_VIOL ((1<<14) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_INT_DIV_BY_ZERO ((1<<16) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_PRIV_INSN ((1<<17) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_ILLEGAL_INSN ((1<<18) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_UNK_MNEMO ((1<<19) | EXCEPT_DO_NOT_UPDATE_PC) +#define EXCEPT_INT_1 ((1<<20) | EXCEPT_DO_NOT_UPDATE_PC) + + +int is_mem_mapped(vm_mngr_t* vm_mngr, uint64_t ad); +uint64_t get_mem_base_addr(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t *addr_base); +unsigned int MEM_LOOKUP(vm_mngr_t* vm_mngr, unsigned int my_size, uint64_t addr); + +int is_mapped(vm_mngr_t* vm_mngr, uint64_t addr, size_t size); +void vm_throw(vm_mngr_t* vm_mngr, unsigned long flags); + +void vm_MEM_WRITE_08(vm_mngr_t* vm_mngr, uint64_t addr, unsigned char src); +void vm_MEM_WRITE_16(vm_mngr_t* vm_mngr, uint64_t addr, unsigned short src); +void vm_MEM_WRITE_32(vm_mngr_t* vm_mngr, uint64_t addr, unsigned int src); +void vm_MEM_WRITE_64(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t src); + +unsigned char vm_MEM_LOOKUP_08(vm_mngr_t* vm_mngr, uint64_t addr); +unsigned short vm_MEM_LOOKUP_16(vm_mngr_t* vm_mngr, uint64_t addr); +unsigned int vm_MEM_LOOKUP_32(vm_mngr_t* vm_mngr, uint64_t addr); +uint64_t vm_MEM_LOOKUP_64(vm_mngr_t* vm_mngr, uint64_t addr); + +void MEM_WRITE_08_PASSTHROUGH(uint64_t addr, unsigned char src); +void MEM_WRITE_16_PASSTHROUGH(uint64_t addr, unsigned short src); +void MEM_WRITE_32_PASSTHROUGH(uint64_t addr, unsigned int src); +void MEM_WRITE_64_PASSTHROUGH(uint64_t addr, uint64_t src); +unsigned char MEM_LOOKUP_08_PASSTHROUGH(uint64_t addr); +unsigned short MEM_LOOKUP_16_PASSTHROUGH(uint64_t addr); +unsigned int MEM_LOOKUP_32_PASSTHROUGH(uint64_t addr); +uint64_t MEM_LOOKUP_64_PASSTHROUGH(uint64_t addr); + +int vm_read_mem(vm_mngr_t* vm_mngr, uint64_t addr, char** buffer_ptr, size_t size); +int vm_write_mem(vm_mngr_t* vm_mngr, uint64_t addr, char *buffer, size_t size); + +void memory_access_list_init(struct memory_access_list * access); +void memory_access_list_reset(struct memory_access_list * access); +void memory_access_list_add(struct memory_access_list * access, uint64_t start, uint64_t stop); + +uint16_t set_endian16(vm_mngr_t* vm_mngr, uint16_t val); +uint32_t set_endian32(vm_mngr_t* vm_mngr, uint32_t val); +uint64_t set_endian64(vm_mngr_t* vm_mngr, uint64_t val); + + +void hexdump(char* m, unsigned int l); + +struct code_bloc_node * create_code_bloc_node(uint64_t ad_start, uint64_t ad_stop); +void add_code_bloc(vm_mngr_t* vm_mngr, struct code_bloc_node* cbp); + +struct memory_page_node * create_memory_page_node(uint64_t ad, size_t size, unsigned int access, const char *name);//memory_page* mp); +void init_memory_page_pool(vm_mngr_t* vm_mngr); +void init_code_bloc_pool(vm_mngr_t* vm_mngr); +void reset_memory_page_pool(vm_mngr_t* vm_mngr); +void reset_code_bloc_pool(vm_mngr_t* vm_mngr); +void dump_code_bloc_pool(vm_mngr_t* vm_mngr); +void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a); +void remove_memory_page(vm_mngr_t* vm_mngr, uint64_t ad); + + +void init_memory_breakpoint(vm_mngr_t* vm_mngr); +void reset_memory_breakpoint(vm_mngr_t* vm_mngr); +void add_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, uint64_t size, unsigned int access); +void remove_memory_breakpoint(vm_mngr_t* vm_mngr, uint64_t ad, unsigned int access); + +void add_memory_page(vm_mngr_t* vm_mngr, struct memory_page_node* mpn); + +void add_mem_read(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size); +void add_mem_write(vm_mngr_t* vm_mngr, uint64_t addr, uint64_t size); +_MIASM_EXPORT void check_invalid_code_blocs(vm_mngr_t* vm_mngr); +_MIASM_EXPORT void check_memory_breakpoint(vm_mngr_t* vm_mngr); +_MIASM_EXPORT void reset_memory_access(vm_mngr_t* vm_mngr); +PyObject* get_memory_read(vm_mngr_t* vm_mngr); +PyObject* get_memory_write(vm_mngr_t* vm_mngr); + + +char* dump(vm_mngr_t* vm_mngr); +void dump_memory_breakpoint_pool(vm_mngr_t* vm_mngr); +PyObject* addr2BlocObj(vm_mngr_t* vm_mngr, uint64_t addr); + + + + +/********************************************/ +unsigned int get_memory_page_max_address(void); +unsigned int get_memory_page_max_user_address(void); + + +int is_mpn_in_tab(vm_mngr_t* vm_mngr, struct memory_page_node* mpn_a); + + +void _func_free(void); +void _func_alloc(void); +unsigned int _get_memory_page_max_address_py(void); +unsigned int _get_memory_page_max_user_address_py(void); +unsigned int _get_memory_page_from_min_ad_py(unsigned int size); + +void _func_malloc_memory_page(void); +void _func_free_memory_page(void); +void _func_virtualalloc_memory_page(void); +void _func_virtualfree_memory_page(void); +void _func_loadlib_fake(void); +void _func_getproc_fake(void); + + +void func_free(void); +void func_alloc(void); +unsigned int get_memory_page_max_address_py(void); +unsigned int get_memory_page_max_user_address_py(void); +unsigned int get_memory_page_from_min_ad_py(unsigned int size); +struct memory_page_node * get_memory_page_from_address(vm_mngr_t*, uint64_t ad, int raise_exception); +void func_malloc_memory_page(void); +void func_free_memory_page(void); +void func_virtualalloc_memory_page(void); +void func_virtualfree_memory_page(void); +void func_loadlib_fake(void); +void func_getproc_fake(void); + +unsigned int access_segment(unsigned int d); +unsigned int access_segment_ok(unsigned int d); + +unsigned int load_segment_limit(unsigned int d); +unsigned int load_segment_limit_ok(unsigned int d); + +unsigned int load_tr_segment_selector(unsigned int d); + +#endif diff --git a/src/miasm/jitter/vm_mngr_py.c b/src/miasm/jitter/vm_mngr_py.c new file mode 100644 index 00000000..dd1bd9b1 --- /dev/null +++ b/src/miasm/jitter/vm_mngr_py.c @@ -0,0 +1,1089 @@ +/* +** 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. +*/ +#include <Python.h> +#include "structmember.h" +#include <stdint.h> +#include <inttypes.h> +#include <signal.h> +#include "compat_py23.h" +#include "queue.h" +#include "vm_mngr.h" +#include "bn.h" +#include "vm_mngr_py.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +extern struct memory_page_list_head memory_page_pool; +extern struct code_bloc_list_head code_bloc_pool; + +#define RAISE(errtype, msg) {PyObject* p; p = PyErr_Format( errtype, msg ); return p;} + + + +/* XXX POC signals */ +VmMngr* global_vmmngr; + +PyObject* _vm_get_exception(unsigned int xcpt) +{ + PyObject*p; + + if (!xcpt) + p = NULL; + else if (xcpt & EXCEPT_CODE_AUTOMOD) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_CODE_AUTOMOD" ); + else if (xcpt & EXCEPT_UNK_EIP) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_EIP" ); + else if (xcpt & EXCEPT_UNK_MEM_AD) + p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNK_MEM_AD" ); + + else p = PyErr_Format( PyExc_RuntimeError, "EXCEPT_UNKNOWN" ); + return p; +} + +static void sig_alarm(int signo) +{ + global_vmmngr->vm_mngr.exception_flags |= BREAK_SIGALARM; + return; +} + +PyObject* set_alarm(VmMngr* self) +{ + global_vmmngr = self; + signal(SIGALRM, sig_alarm); + + Py_INCREF(Py_None); + return Py_None; +} + + + +PyObject* vm_add_memory_page(VmMngr* self, PyObject* args) +{ + PyObject *addr; + PyObject *access; + PyObject *item_str; + PyObject *name=NULL; + uint64_t buf_size; + size_t buf_size_st; + char* buf_data; + Py_ssize_t length; + uint64_t page_addr; + uint64_t page_access; + const char *name_ptr; + + struct memory_page_node * mpn; + + if (!PyArg_ParseTuple(args, "OOO|O", &addr, &access, &item_str, &name)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(addr, page_addr); + PyGetInt_uint64_t(access, page_access); + + if(!PyBytes_Check(item_str)) + RAISE(PyExc_TypeError,"arg must be bytes"); + + buf_size = PyBytes_Size(item_str); + PyBytes_AsStringAndSize(item_str, &buf_data, &length); + + if (name == NULL) { + name_ptr = (char*)""; + } else { + PyGetStr(name_ptr, name); + } + mpn = create_memory_page_node(page_addr, (size_t)buf_size, (unsigned int)page_access, name_ptr); + if (mpn == NULL) + RAISE(PyExc_TypeError,"cannot create page"); + if (is_mpn_in_tab(&self->vm_mngr, mpn)) { + free(mpn->ad_hp); + free(mpn); + RAISE(PyExc_TypeError,"known page in memory"); + } + + if (buf_size > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + buf_size_st = (size_t) buf_size; + + memcpy(mpn->ad_hp, buf_data, buf_size_st); + add_memory_page(&self->vm_mngr, mpn); + + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject* vm_remove_memory_page(VmMngr* self, PyObject* args) +{ + PyObject *addr; + uint64_t page_addr; + + if (!PyArg_ParseTuple(args, "O", &addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(addr, page_addr); + + remove_memory_page(&self->vm_mngr, page_addr); + + Py_INCREF(Py_None); + return Py_None; + + +} + +PyObject* vm_set_mem_access(VmMngr* self, PyObject* args) +{ + PyObject *addr; + PyObject *access; + uint64_t page_addr; + uint64_t page_access; + struct memory_page_node * mpn; + + if (!PyArg_ParseTuple(args, "OO", &addr, &access)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(addr, page_addr); + PyGetInt_uint64_t(access, page_access); + + mpn = get_memory_page_from_address(&self->vm_mngr, page_addr, 1); + if (!mpn){ + PyErr_SetString(PyExc_RuntimeError, "cannot find address"); + return 0; + } + + mpn->access = page_access; + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_set_mem(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_buffer; + Py_ssize_t py_length; + + char * buffer; + Py_ssize_t pysize; + uint64_t addr; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_buffer)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + + if (!PyBytes_Check(py_buffer)) + RAISE(PyExc_TypeError,"arg must be bytes"); + + pysize = PyBytes_Size(py_buffer); + if (pysize < 0) { + RAISE(PyExc_TypeError,"Python error"); + } + PyBytes_AsStringAndSize(py_buffer, &buffer, &py_length); + + ret = vm_write_mem(&self->vm_mngr, addr, buffer, pysize); + if (ret < 0) + RAISE(PyExc_TypeError, "Error in set_mem"); + + add_mem_write(&self->vm_mngr, addr, (size_t)pysize); + check_invalid_code_blocs(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + + + +PyObject* vm_get_mem_access(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + uint64_t page_addr; + struct memory_page_node * mpn; + + if (!PyArg_ParseTuple(args, "O", &py_addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, page_addr); + + mpn = get_memory_page_from_address(&self->vm_mngr, page_addr, 1); + if (!mpn){ + PyErr_SetString(PyExc_RuntimeError, "cannot find address"); + return 0; + } + + return PyLong_FromUnsignedLongLong((uint64_t)mpn->access); +} + +PyObject* vm_get_mem(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_len; + + uint64_t addr; + uint64_t size; + size_t size_st; + PyObject *obj_out; + char * buf_out; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_len)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint64_t(py_len, size); + + if (size > SIZE_MAX) { + fprintf(stderr, "Size too big\n"); + exit(EXIT_FAILURE); + } + size_st = (size_t) size; + + ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, size_st); + if (ret < 0) { + RAISE(PyExc_RuntimeError,"Cannot find address"); + } + + obj_out = PyBytes_FromStringAndSize(buf_out, size_st); + free(buf_out); + return obj_out; +} + +PyObject* vm_get_u8(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + + uint64_t addr; + PyObject *obj_out; + char * buf_out; + int ret; + uint32_t value; + + if (!PyArg_ParseTuple(args, "O", &py_addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + + ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 1); + if (ret < 0) { + RAISE(PyExc_RuntimeError,"Cannot find address"); + } + + value = *(uint8_t*)buf_out; + + obj_out = PyLong_FromUnsignedLongLong(value); + free(buf_out); + return obj_out; +} + +PyObject* vm_get_u16(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + + uint64_t addr; + PyObject *obj_out; + char * buf_out; + int ret; + uint16_t value; + + if (!PyArg_ParseTuple(args, "O", &py_addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + + ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 2); + if (ret < 0) { + RAISE(PyExc_RuntimeError,"Cannot find address"); + } + + value = set_endian16(&self->vm_mngr, *(uint16_t*)buf_out); + + obj_out = PyLong_FromUnsignedLongLong(value); + free(buf_out); + return obj_out; +} + +PyObject* vm_get_u32(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + + uint64_t addr; + PyObject *obj_out; + char * buf_out; + int ret; + uint32_t value; + + if (!PyArg_ParseTuple(args, "O", &py_addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + + ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 4); + if (ret < 0) { + RAISE(PyExc_RuntimeError,"Cannot find address"); + } + + value = set_endian32(&self->vm_mngr, *(uint32_t*)buf_out); + + obj_out = PyLong_FromUnsignedLongLong(value); + free(buf_out); + return obj_out; +} + + +PyObject* vm_get_u64(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + + uint64_t addr; + PyObject *obj_out; + char * buf_out; + int ret; + uint64_t value; + + if (!PyArg_ParseTuple(args, "O", &py_addr)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + + ret = vm_read_mem(&self->vm_mngr, addr, &buf_out, 8); + if (ret < 0) { + RAISE(PyExc_RuntimeError,"Cannot find address"); + } + + value = set_endian64(&self->vm_mngr, *(uint64_t*)buf_out); + + obj_out = PyLong_FromUnsignedLongLong(value); + free(buf_out); + return obj_out; +} + + +PyObject* vm_set_u8(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_val; + uint8_t value; + uint64_t addr; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint8_t(py_val, value); + + ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 1); + if (ret < 0) + RAISE(PyExc_TypeError, "Error in set_mem"); + + add_mem_write(&self->vm_mngr, addr, 1); + check_invalid_code_blocs(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_set_u16(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_val; + uint16_t value; + + uint64_t addr; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint16_t(py_val, value); + + value = set_endian16(&self->vm_mngr, value); + ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 2); + if (ret < 0) + RAISE(PyExc_TypeError, "Error in set_mem"); + + add_mem_write(&self->vm_mngr, addr, 2); + check_invalid_code_blocs(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_set_u32(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_val; + uint32_t value; + uint64_t addr; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint32_t(py_val, value); + + value = set_endian32(&self->vm_mngr, value); + + ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 4); + if (ret < 0) + RAISE(PyExc_TypeError, "Error in set_mem"); + + add_mem_write(&self->vm_mngr, addr, 4); + check_invalid_code_blocs(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_set_u64(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_val; + uint64_t value; + uint64_t addr; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_val)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint64_t(py_val, value); + + value = set_endian64(&self->vm_mngr, value); + + ret = vm_write_mem(&self->vm_mngr, addr, (char*)&value, 8); + if (ret < 0) + RAISE(PyExc_TypeError, "Error in set_mem"); + + add_mem_write(&self->vm_mngr, addr, 8); + check_invalid_code_blocs(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + + + + + +PyObject* vm_add_memory_breakpoint(VmMngr* self, PyObject* args) +{ + PyObject *ad; + PyObject *size; + PyObject *access; + + uint64_t b_ad; + uint64_t b_size; + uint64_t b_access; + + if (!PyArg_ParseTuple(args, "OOO", &ad, &size, &access)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(ad, b_ad); + PyGetInt_uint64_t(size, b_size); + PyGetInt_uint64_t(access, b_access); + + add_memory_breakpoint(&self->vm_mngr, b_ad, b_size, (unsigned int)b_access); + + /* Raise exception in the following pattern: + - set_mem(XXX) + - add_memory_breakpoint(XXX) + -> Here, there is a pending breakpoint not raise + */ + check_memory_breakpoint(&self->vm_mngr); + + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject* vm_remove_memory_breakpoint(VmMngr* self, PyObject* args) +{ + PyObject *ad; + PyObject *access; + uint64_t b_ad; + uint64_t b_access; + + if (!PyArg_ParseTuple(args, "OO", &ad, &access)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(ad, b_ad); + PyGetInt_uint64_t(access, b_access); + remove_memory_breakpoint(&self->vm_mngr, b_ad, (unsigned int)b_access); + + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject* vm_set_exception(VmMngr* self, PyObject* args) +{ + PyObject *item1; + uint64_t exception_flags; + + if (!PyArg_ParseTuple(args, "O", &item1)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(item1, exception_flags); + + self->vm_mngr.exception_flags = exception_flags; + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_get_exception(VmMngr* self, PyObject* args) +{ + return PyLong_FromUnsignedLongLong((uint64_t)self->vm_mngr.exception_flags); +} + + + + +PyObject* vm_init_memory_page_pool(VmMngr* self, PyObject* args) +{ + init_memory_page_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_init_code_bloc_pool(VmMngr* self, PyObject* args) +{ + init_code_bloc_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_init_memory_breakpoint(VmMngr* self, PyObject* args) +{ + init_memory_breakpoint(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_reset_memory_breakpoint(VmMngr* self, PyObject* args) +{ + reset_memory_breakpoint(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_reset_memory_access(VmMngr* self, PyObject* args) +{ + reset_memory_access(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* py_add_mem_read(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_size; + uint64_t addr; + uint64_t size; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint64_t(py_size, size); + add_mem_read(&self->vm_mngr, addr, size); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* py_add_mem_write(VmMngr* self, PyObject* args) +{ + PyObject *py_addr; + PyObject *py_size; + uint64_t addr; + uint64_t size; + + if (!PyArg_ParseTuple(args, "OO", &py_addr, &py_size)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(py_addr, addr); + PyGetInt_uint64_t(py_size, size); + add_mem_write(&self->vm_mngr, addr, size); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_check_invalid_code_blocs(VmMngr* self, PyObject* args) +{ + check_invalid_code_blocs(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_check_memory_breakpoint(VmMngr* self, PyObject* args) +{ + check_memory_breakpoint(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; +} + +PyObject *vm_dump(PyObject* self) +{ + char* buf_final; + PyObject* ret_obj; + + buf_final = dump(&((VmMngr* )self)->vm_mngr); + ret_obj = PyUnicode_FromString(buf_final); + free(buf_final); + return ret_obj; +} + +PyObject* vm_dump_memory_breakpoint(VmMngr* self, PyObject* args) +{ + dump_memory_breakpoint_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; +} + + +PyObject* vm_get_all_memory(VmMngr* self, PyObject* args) +{ + PyObject *o; + struct memory_page_node * mpn; + PyObject *dict; + PyObject *dict2; + int i; + + + dict = PyDict_New(); + + for (i=0;i<self->vm_mngr.memory_pages_number; i++) { + mpn = &self->vm_mngr.memory_pages_array[i]; + + dict2 = PyDict_New(); + + o = PyBytes_FromStringAndSize(mpn->ad_hp, mpn->size); + PyDict_SetItemString(dict2, "data", o); + Py_DECREF(o); + + o = PyLong_FromLong((long)mpn->size); + PyDict_SetItemString(dict2, "size", o); + Py_DECREF(o); + + o = PyLong_FromLong((long)mpn->access); + PyDict_SetItemString(dict2, "access", o); + Py_DECREF(o); + + o = PyLong_FromUnsignedLongLong(mpn->ad); + PyDict_SetItem(dict, o, dict2); + Py_DECREF(o); + Py_DECREF(dict2); + } + return dict; +} + + +PyObject* vm_reset_memory_page_pool(VmMngr* self, PyObject* args) +{ + reset_memory_page_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + +PyObject* vm_reset_code_bloc_pool(VmMngr* self, PyObject* args) +{ + reset_code_bloc_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + + +PyObject* vm_add_code_bloc(VmMngr *self, PyObject *args) +{ + PyObject *item1; + PyObject *item2; + uint64_t ad_start, ad_stop, ad_code = 0; + + struct code_bloc_node * cbp; + + if (!PyArg_ParseTuple(args, "OO", &item1, &item2)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(item1, ad_start); + PyGetInt_uint64_t(item2, ad_stop); + + cbp = create_code_bloc_node(ad_start, ad_stop); + cbp->ad_start = ad_start; + cbp->ad_stop = ad_stop; + cbp->ad_code = ad_code; + add_code_bloc(&self->vm_mngr, cbp); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* vm_dump_code_bloc_pool(VmMngr* self) +{ + dump_code_bloc_pool(&self->vm_mngr); + Py_INCREF(Py_None); + return Py_None; + +} + + + +PyObject* vm_is_mapped(VmMngr* self, PyObject* args) +{ + PyObject *ad; + PyObject *size; + uint64_t b_ad; + size_t b_size; + int ret; + + if (!PyArg_ParseTuple(args, "OO", &ad, &size)) + RAISE(PyExc_TypeError,"Cannot parse arguments"); + + PyGetInt_uint64_t(ad, b_ad); + PyGetInt_size_t(size, b_size); + ret = is_mapped(&self->vm_mngr, b_ad, b_size); + return PyLong_FromUnsignedLongLong((uint64_t)ret); +} + +PyObject* vm_get_memory_read(VmMngr* self, PyObject* args) +{ + PyObject* result; + result = get_memory_read(&self->vm_mngr); + Py_INCREF(result); + return result; +} + +PyObject* vm_get_memory_write(VmMngr* self, PyObject* args) +{ + PyObject* result; + result = get_memory_write(&self->vm_mngr); + Py_INCREF(result); + return result; +} + + + +static PyObject * +vm_set_big_endian(VmMngr *self, PyObject *value, void *closure) +{ + self->vm_mngr.sex = __BIG_ENDIAN; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +vm_set_little_endian(VmMngr *self, PyObject *value, void *closure) +{ + self->vm_mngr.sex = __LITTLE_ENDIAN; + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +vm_is_little_endian(VmMngr *self, PyObject *value, void *closure) +{ + if (self->vm_mngr.sex == __BIG_ENDIAN) { + return PyLong_FromUnsignedLongLong(0); + } else { + return PyLong_FromUnsignedLongLong(1); + } +} + + +static void +VmMngr_dealloc(VmMngr* self) +{ + vm_reset_memory_page_pool(self, NULL); + vm_reset_code_bloc_pool(self, NULL); + vm_reset_memory_breakpoint(self, NULL); + Py_TYPE(self)->tp_free((PyObject*)self); +} + + +static PyObject * +VmMngr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + VmMngr *self; + + self = (VmMngr *)type->tp_alloc(type, 0); + return (PyObject *)self; +} + +static PyObject * +VmMngr_get_vmmngr(VmMngr *self, void *closure) +{ + return PyLong_FromUnsignedLongLong((uint64_t)(intptr_t)&(self->vm_mngr)); +} + +static int +VmMngr_set_vmmngr(VmMngr *self, PyObject *value, void *closure) +{ + PyErr_SetString(PyExc_TypeError, "immutable vmmngr"); + return -1; +} + +static PyMemberDef VmMngr_members[] = { + {NULL} /* Sentinel */ +}; + +static PyMethodDef VmMngr_methods[] = { + {"init_memory_page_pool", (PyCFunction)vm_init_memory_page_pool, METH_VARARGS, + "init_memory_page_pool() -> Initialize the VmMngr memory"}, + {"init_memory_breakpoint", (PyCFunction)vm_init_memory_breakpoint, METH_VARARGS, + "init_memory_breakpoint() -> Initialize the VmMngr memory breakpoints"}, + {"init_code_bloc_pool",(PyCFunction)vm_init_code_bloc_pool, METH_VARARGS, + "init_code_bloc_pool() -> Initialize the VmMngr jitted code blocks"}, + {"set_mem_access", (PyCFunction)vm_set_mem_access, METH_VARARGS, + "set_mem_access(address, access) -> Change the protection of the page at @address with @access"}, + {"set_mem", (PyCFunction)vm_set_mem, METH_VARARGS, + "set_mem(address, data) -> Set a @data in memory at @address"}, + {"is_mapped", (PyCFunction)vm_is_mapped, METH_VARARGS, + "is_mapped(address, size) -> Check if the memory region at @address of @size bytes is fully mapped"}, + {"add_code_bloc",(PyCFunction)vm_add_code_bloc, METH_VARARGS, + "add_code_bloc(address_start, address_stop) -> Add a jitted code block between [@address_start, @address_stop["}, + {"get_mem_access", (PyCFunction)vm_get_mem_access, METH_VARARGS, + "get_mem_access(address) -> Retrieve the memory protection of the page at @address"}, + {"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS, + "get_mem(addr, size) -> Get the memory content at @address of @size bytes"}, + + {"get_u8", (PyCFunction)vm_get_u8, METH_VARARGS, + "get_u8(addr) -> Get a u8 at @address of @size bytes (vm endianness)"}, + {"get_u16", (PyCFunction)vm_get_u16, METH_VARARGS, + "get_u16(addr) -> Get a u16 at @address of @size bytes (vm endianness)"}, + {"get_u32", (PyCFunction)vm_get_u32, METH_VARARGS, + "get_u32(addr) -> Get a u32 at @address of @size bytes (vm endianness)"}, + {"get_u64", (PyCFunction)vm_get_u64, METH_VARARGS, + "get_u64(addr) -> Get a u64 at @address of @size bytes (vm endianness)"}, + + + {"set_u8", (PyCFunction)vm_set_u8, METH_VARARGS, + "set_u8(addr, value) -> Set a u8 at @address of @size bytes (vm endianness)"}, + {"set_u16", (PyCFunction)vm_set_u16, METH_VARARGS, + "set_u16(addr, value) -> Set a u16 at @address of @size bytes (vm endianness)"}, + {"set_u32", (PyCFunction)vm_set_u32, METH_VARARGS, + "set_u32(addr, value) -> Set a u32 at @address of @size bytes (vm endianness)"}, + {"set_u64", (PyCFunction)vm_set_u64, METH_VARARGS, + "set_u64(addr, value) -> Set a u64 at @address of @size bytes (vm endianness)"}, + + {"add_memory_page",(PyCFunction)vm_add_memory_page, METH_VARARGS, + "add_memory_page(address, access, content [, cmt]) -> Maps a memory page at @address of len(@content) bytes containing @content with protection @access\n" + "@cmt is a comment linked to the memory page"}, + {"remove_memory_page",(PyCFunction)vm_remove_memory_page, METH_VARARGS, + "remove_memory_page(address) -> removes a previously allocated memory page at @address"}, + {"add_memory_breakpoint",(PyCFunction)vm_add_memory_breakpoint, METH_VARARGS, + "add_memory_breakpoint(address, size, access) -> Add a memory breakpoint at @address of @size bytes with @access type"}, + {"remove_memory_breakpoint",(PyCFunction)vm_remove_memory_breakpoint, METH_VARARGS, + "remove_memory_breakpoint(address, access) -> Remove a memory breakpoint at @address with @access type"}, + {"set_exception", (PyCFunction)vm_set_exception, METH_VARARGS, + "set_exception(exception) -> Set the VmMngr exception flags to @exception"}, + {"dump_memory_breakpoint", (PyCFunction)vm_dump_memory_breakpoint, METH_VARARGS, + "dump_memory_breakpoint() -> Lists each memory breakpoint"}, + {"get_all_memory",(PyCFunction)vm_get_all_memory, METH_VARARGS, + "get_all_memory() -> Returns a dictionary representing the VmMngr memory.\n" + "Keys are the addresses of each memory page.\n" + "Values are another dictionary containing page properties ('data', 'size', 'access')" + }, + {"reset_memory_page_pool", (PyCFunction)vm_reset_memory_page_pool, METH_VARARGS, + "reset_memory_page_pool() -> Remove all memory pages"}, + {"reset_memory_breakpoint", (PyCFunction)vm_reset_memory_breakpoint, METH_VARARGS, + "reset_memory_breakpoint() -> Remove all memory breakpoints"}, + {"reset_code_bloc_pool", (PyCFunction)vm_reset_code_bloc_pool, METH_VARARGS, + "reset_code_bloc_pool() -> Remove all jitted blocks"}, + {"set_alarm", (PyCFunction)set_alarm, METH_VARARGS, + "set_alarm() -> Force a timer based alarm during a code emulation"}, + {"get_exception",(PyCFunction)vm_get_exception, METH_VARARGS, + "get_exception() -> Returns the VmMngr exception flags"}, + {"set_big_endian",(PyCFunction)vm_set_big_endian, METH_VARARGS, + "set_big_endian() -> Set the VmMngr to Big Endian"}, + {"set_little_endian",(PyCFunction)vm_set_little_endian, METH_VARARGS, + "set_little_endian() -> Set the VmMngr to Little Endian"}, + {"is_little_endian",(PyCFunction)vm_is_little_endian, METH_VARARGS, + "is_little_endian() -> Return True if the VmMngr is Little Endian"}, + {"get_memory_read",(PyCFunction)vm_get_memory_read, METH_VARARGS, + "get_memory_read() -> Retrieve last instruction READ access\n" + "This function is only valid in a memory breakpoint callback." + }, + {"get_memory_write",(PyCFunction)vm_get_memory_write, METH_VARARGS, + "get_memory_write() -> Retrieve last instruction WRITE access\n" + "This function is only valid in a memory breakpoint callback." + }, + {"reset_memory_access",(PyCFunction)vm_reset_memory_access, METH_VARARGS, + "reset_memory_access() -> Reset last memory READ/WRITE"}, + {"add_mem_read",(PyCFunction)py_add_mem_read, METH_VARARGS, + "add_mem_read(address, size) -> Add a READ access at @address of @size bytes"}, + {"add_mem_write",(PyCFunction)py_add_mem_write, METH_VARARGS, + "add_mem_write(address, size) -> Add a WRITE access at @address of @size bytes"}, + {"check_invalid_code_blocs",(PyCFunction)vm_check_invalid_code_blocs, METH_VARARGS, + "check_invalid_code_blocs() -> Set the AUTOMOD flag in exception in case of automodified code"}, + {"check_memory_breakpoint",(PyCFunction)vm_check_memory_breakpoint, METH_VARARGS, + "check_memory_breakpoint() -> Set the BREAKPOINT_MEMORY flag in exception in case of memory breakpoint occurred"}, + + {NULL} /* Sentinel */ +}; + +static int +VmMngr_init(VmMngr *self, PyObject *args, PyObject *kwds) +{ + memset(&(self->vm_mngr), 0, sizeof(self->vm_mngr)); + return 0; +} + +static PyGetSetDef VmMngr_getseters[] = { + {"vmmngr", + (getter)VmMngr_get_vmmngr, (setter)VmMngr_set_vmmngr, + "vmmngr object", + NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject VmMngrType = { + PyVarObject_HEAD_INIT(NULL, 0) + "VmMngr", /*tp_name*/ + sizeof(VmMngr), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)VmMngr_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + vm_dump, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "VmMngr object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + VmMngr_methods, /* tp_methods */ + VmMngr_members, /* tp_members */ + VmMngr_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)VmMngr_init, /* tp_init */ + 0, /* tp_alloc */ + VmMngr_new, /* tp_new */ +}; + +static PyMethodDef VmMngr_Methods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ + +}; + +char vm_mngr_mod_docs[] = "vm_mngr module."; +char vm_mngr_mod_name[] = "VmMngr"; + + +MOD_INIT(VmMngr) +{ + PyObject *module = NULL; + + MOD_DEF(module, "VmMngr", "vm_mngr module", VmMngr_Methods); + + if (module == NULL) + RET_MODULE; + + if (PyType_Ready(&VmMngrType) < 0) + RET_MODULE; + + Py_INCREF(&VmMngrType); + if (PyModule_AddObject(module, "Vm", (PyObject *)&VmMngrType) < 0) + RET_MODULE; + + RET_MODULE; +} + +bn_t PyLong_to_bn(PyObject* py_long) +{ + int j; + uint64_t tmp_mask; + PyObject* py_tmp; + PyObject* py_long_tmp; + PyObject* cst_32; + PyObject* cst_ffffffff; + bn_t bn; + + cst_ffffffff = PyLong_FromLong(0xffffffff); + cst_32 = PyLong_FromLong(32); + bn = bignum_from_int(0); + + for (j = 0; j < BN_BYTE_SIZE; j += 4) { + py_tmp = PyObject_CallMethod(py_long, "__and__", "O", cst_ffffffff); + py_long_tmp = PyObject_CallMethod(py_long, "__rshift__", "O", cst_32); + Py_DECREF(py_long); + py_long = py_long_tmp; + tmp_mask = PyLong_AsUnsignedLongLongMask(py_tmp); + Py_DECREF(py_tmp); + bn = bignum_or(bn, bignum_lshift(bignum_from_uint64(tmp_mask), 8 * j)); + } + + Py_DECREF(cst_32); + Py_DECREF(cst_ffffffff); + + return bn; +} + +PyObject* bn_to_PyLong(bn_t bn) +{ + int j; + PyObject* py_long; + PyObject* py_long_new; + PyObject* py_tmp; + PyObject* cst_32; + uint64_t tmp; + + py_long = PyLong_FromLong(0); + cst_32 = PyLong_FromLong(32); + + for (j = BN_BYTE_SIZE - 4; j >= 0 ; j -= 4) { + tmp = bignum_to_uint64(bignum_mask(bignum_rshift(bn, 8 * j), 32)); + py_tmp = PyLong_FromUnsignedLong((unsigned long)tmp); + py_long_new = PyObject_CallMethod(py_long, "__lshift__", "O", cst_32); + Py_DECREF(py_long); + py_long = PyObject_CallMethod(py_long_new, "__add__", "O", py_tmp); + Py_DECREF(py_long_new); + Py_DECREF(py_tmp); + } + + Py_DECREF(cst_32); + + return py_long; +} diff --git a/src/miasm/jitter/vm_mngr_py.h b/src/miasm/jitter/vm_mngr_py.h new file mode 100644 index 00000000..a8f7dcd0 --- /dev/null +++ b/src/miasm/jitter/vm_mngr_py.h @@ -0,0 +1,17 @@ +#ifndef VM_MNGR_PY_H +#define VM_MNGR_PY_H + +#ifdef _WIN32 +#define SIGALRM 0 +#endif + +typedef struct { + PyObject_HEAD + PyObject *vmmngr; + vm_mngr_t vm_mngr; +} VmMngr; + +#endif// VM_MNGR_PY_H + +bn_t PyLong_to_bn(PyObject* py_long); +PyObject* bn_to_PyLong(bn_t bn); |