You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
945 lines
27 KiB
945 lines
27 KiB
/* Capstone Disassembler Engine */ |
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */ |
|
|
|
#include <stdio.h> // debug |
|
#include <string.h> |
|
#include <caml/mlvalues.h> |
|
#include <caml/memory.h> |
|
#include <caml/alloc.h> |
|
#include <caml/fail.h> |
|
|
|
#include "../../include/capstone.h" |
|
|
|
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) |
|
|
|
|
|
// count the number of positive members in @list |
|
static unsigned int list_count(uint8_t *list, unsigned int max) |
|
{ |
|
unsigned int i; |
|
|
|
for(i = 0; i < max; i++) |
|
if (list[i] == 0) |
|
return i; |
|
|
|
return max; |
|
} |
|
|
|
CAMLprim value _cs_disasm(cs_arch arch, csh handle, const uint8_t * code, size_t code_len, uint64_t addr, size_t count) |
|
{ |
|
CAMLparam0(); |
|
CAMLlocal5(list, cons, rec_insn, array, tmp); |
|
CAMLlocal4(arch_info, op_info_val, tmp2, tmp3); |
|
cs_insn *insn; |
|
size_t c; |
|
|
|
list = Val_emptylist; |
|
|
|
c = cs_disasm(handle, code, code_len, addr, count, &insn); |
|
if (c) { |
|
//printf("Found %lu insn, addr: %lx\n", c, addr); |
|
uint64_t j; |
|
for (j = c; j > 0; j--) { |
|
unsigned int lcount, i; |
|
cons = caml_alloc(2, 0); |
|
|
|
rec_insn = caml_alloc(10, 0); |
|
Store_field(rec_insn, 0, Val_int(insn[j-1].id)); |
|
Store_field(rec_insn, 1, Val_int(insn[j-1].address)); |
|
Store_field(rec_insn, 2, Val_int(insn[j-1].size)); |
|
|
|
// copy raw bytes of instruction |
|
lcount = insn[j-1].size; |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].bytes[i])); |
|
} |
|
} else |
|
array = Atom(0); // empty list |
|
Store_field(rec_insn, 3, array); |
|
|
|
Store_field(rec_insn, 4, caml_copy_string(insn[j-1].mnemonic)); |
|
Store_field(rec_insn, 5, caml_copy_string(insn[j-1].op_str)); |
|
|
|
// copy read registers |
|
if (insn[0].detail) { |
|
lcount = (insn[j-1]).detail->regs_read_count; |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].detail->regs_read[i])); |
|
} |
|
} else |
|
array = Atom(0); // empty list |
|
} else |
|
array = Atom(0); // empty list |
|
Store_field(rec_insn, 6, array); |
|
|
|
if (insn[0].detail) { |
|
lcount = (insn[j-1]).detail->regs_write_count; |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].detail->regs_write[i])); |
|
} |
|
} else |
|
array = Atom(0); // empty list |
|
} else |
|
array = Atom(0); // empty list |
|
Store_field(rec_insn, 7, array); |
|
|
|
if (insn[0].detail) { |
|
lcount = (insn[j-1]).detail->groups_count; |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].detail->groups[i])); |
|
} |
|
} else |
|
array = Atom(0); // empty list |
|
} else |
|
array = Atom(0); // empty list |
|
Store_field(rec_insn, 8, array); |
|
|
|
if (insn[j-1].detail) { |
|
switch(arch) { |
|
case CS_ARCH_ARM: |
|
arch_info = caml_alloc(1, 0); |
|
|
|
op_info_val = caml_alloc(10, 0); |
|
Store_field(op_info_val, 0, Val_bool(insn[j-1].detail->arm.usermode)); |
|
Store_field(op_info_val, 1, Val_int(insn[j-1].detail->arm.vector_size)); |
|
Store_field(op_info_val, 2, Val_int(insn[j-1].detail->arm.vector_data)); |
|
Store_field(op_info_val, 3, Val_int(insn[j-1].detail->arm.cps_mode)); |
|
Store_field(op_info_val, 4, Val_int(insn[j-1].detail->arm.cps_flag)); |
|
Store_field(op_info_val, 5, Val_int(insn[j-1].detail->arm.cc)); |
|
Store_field(op_info_val, 6, Val_bool(insn[j-1].detail->arm.update_flags)); |
|
Store_field(op_info_val, 7, Val_bool(insn[j-1].detail->arm.writeback)); |
|
Store_field(op_info_val, 8, Val_int(insn[j-1].detail->arm.mem_barrier)); |
|
|
|
lcount = insn[j-1].detail->arm.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(4, 0); |
|
switch(insn[j-1].detail->arm.operands[i].type) { |
|
case ARM_OP_REG: |
|
case ARM_OP_SYSREG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm.operands[i].reg)); |
|
break; |
|
case ARM_OP_CIMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm.operands[i].imm)); |
|
break; |
|
case ARM_OP_PIMM: |
|
tmp = caml_alloc(1, 3); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm.operands[i].imm)); |
|
break; |
|
case ARM_OP_IMM: |
|
tmp = caml_alloc(1, 4); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm.operands[i].imm)); |
|
break; |
|
case ARM_OP_FP: |
|
tmp = caml_alloc(1, 5); |
|
Store_field(tmp, 0, caml_copy_double(insn[j-1].detail->arm.operands[i].fp)); |
|
break; |
|
case ARM_OP_MEM: |
|
tmp = caml_alloc(1, 6); |
|
tmp3 = caml_alloc(5, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->arm.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->arm.operands[i].mem.index)); |
|
Store_field(tmp3, 2, Val_int(insn[j-1].detail->arm.operands[i].mem.scale)); |
|
Store_field(tmp3, 3, Val_int(insn[j-1].detail->arm.operands[i].mem.disp)); |
|
Store_field(tmp3, 4, Val_int(insn[j-1].detail->arm.operands[i].mem.lshift)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
case ARM_OP_SETEND: |
|
tmp = caml_alloc(1, 7); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm.operands[i].setend)); |
|
break; |
|
default: break; |
|
} |
|
tmp3 = caml_alloc(2, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->arm.operands[i].shift.type)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->arm.operands[i].shift.value)); |
|
Store_field(tmp2, 0, Val_int(insn[j-1].detail->arm.operands[i].vector_index)); |
|
Store_field(tmp2, 1, tmp3); |
|
Store_field(tmp2, 2, tmp); |
|
Store_field(tmp2, 3, Val_bool(insn[j-1].detail->arm.operands[i].subtracted)); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty list |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 9, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
case CS_ARCH_ARM64: |
|
arch_info = caml_alloc(1, 1); |
|
|
|
op_info_val = caml_alloc(4, 0); |
|
Store_field(op_info_val, 0, Val_int(insn[j-1].detail->arm64.cc)); |
|
Store_field(op_info_val, 1, Val_bool(insn[j-1].detail->arm64.update_flags)); |
|
Store_field(op_info_val, 2, Val_bool(insn[j-1].detail->arm64.writeback)); |
|
|
|
lcount = insn[j-1].detail->arm64.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(6, 0); |
|
switch(insn[j-1].detail->arm64.operands[i].type) { |
|
case ARM64_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].reg)); |
|
break; |
|
case ARM64_OP_CIMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].imm)); |
|
break; |
|
case ARM64_OP_IMM: |
|
tmp = caml_alloc(1, 3); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].imm)); |
|
break; |
|
case ARM64_OP_FP: |
|
tmp = caml_alloc(1, 4); |
|
Store_field(tmp, 0, caml_copy_double(insn[j-1].detail->arm64.operands[i].fp)); |
|
break; |
|
case ARM64_OP_MEM: |
|
tmp = caml_alloc(1, 5); |
|
tmp3 = caml_alloc(3, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->arm64.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->arm64.operands[i].mem.index)); |
|
Store_field(tmp3, 2, Val_int(insn[j-1].detail->arm64.operands[i].mem.disp)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
case ARM64_OP_REG_MRS: |
|
tmp = caml_alloc(1, 6); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].reg)); |
|
break; |
|
case ARM64_OP_REG_MSR: |
|
tmp = caml_alloc(1, 7); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].reg)); |
|
break; |
|
case ARM64_OP_PSTATE: |
|
tmp = caml_alloc(1, 8); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].pstate)); |
|
break; |
|
case ARM64_OP_SYS: |
|
tmp = caml_alloc(1, 9); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].sys)); |
|
break; |
|
case ARM64_OP_PREFETCH: |
|
tmp = caml_alloc(1, 10); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].prefetch)); |
|
break; |
|
case ARM64_OP_BARRIER: |
|
tmp = caml_alloc(1, 11); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->arm64.operands[i].barrier)); |
|
break; |
|
default: break; |
|
} |
|
tmp3 = caml_alloc(2, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->arm64.operands[i].shift.type)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->arm64.operands[i].shift.value)); |
|
|
|
Store_field(tmp2, 0, Val_int(insn[j-1].detail->arm64.operands[i].vector_index)); |
|
Store_field(tmp2, 1, Val_int(insn[j-1].detail->arm64.operands[i].vas)); |
|
Store_field(tmp2, 2, Val_int(insn[j-1].detail->arm64.operands[i].vess)); |
|
Store_field(tmp2, 3, tmp3); |
|
Store_field(tmp2, 4, Val_int(insn[j-1].detail->arm64.operands[i].ext)); |
|
Store_field(tmp2, 5, tmp); |
|
|
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 3, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
case CS_ARCH_MIPS: |
|
arch_info = caml_alloc(1, 2); |
|
|
|
op_info_val = caml_alloc(1, 0); |
|
|
|
lcount = insn[j-1].detail->mips.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(1, 0); |
|
switch(insn[j-1].detail->mips.operands[i].type) { |
|
case MIPS_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->mips.operands[i].reg)); |
|
break; |
|
case MIPS_OP_IMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->mips.operands[i].imm)); |
|
break; |
|
case MIPS_OP_MEM: |
|
tmp = caml_alloc(1, 3); |
|
tmp3 = caml_alloc(2, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->mips.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->mips.operands[i].mem.disp)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
default: break; |
|
} |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 0, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
case CS_ARCH_X86: |
|
arch_info = caml_alloc(1, 3); |
|
|
|
op_info_val = caml_alloc(15, 0); |
|
|
|
// fill prefix |
|
lcount = list_count(insn[j-1].detail->x86.prefix, ARR_SIZE(insn[j-1].detail->x86.prefix)); |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].detail->x86.prefix[i])); |
|
} |
|
} else |
|
array = Atom(0); |
|
Store_field(op_info_val, 0, array); |
|
|
|
// fill opcode |
|
lcount = list_count(insn[j-1].detail->x86.opcode, ARR_SIZE(insn[j-1].detail->x86.opcode)); |
|
if (lcount) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
Store_field(array, i, Val_int(insn[j-1].detail->x86.opcode[i])); |
|
} |
|
} else |
|
array = Atom(0); |
|
Store_field(op_info_val, 1, array); |
|
|
|
Store_field(op_info_val, 2, Val_int(insn[j-1].detail->x86.rex)); |
|
|
|
Store_field(op_info_val, 3, Val_int(insn[j-1].detail->x86.addr_size)); |
|
|
|
Store_field(op_info_val, 4, Val_int(insn[j-1].detail->x86.modrm)); |
|
|
|
Store_field(op_info_val, 5, Val_int(insn[j-1].detail->x86.sib)); |
|
|
|
Store_field(op_info_val, 6, Val_int(insn[j-1].detail->x86.disp)); |
|
|
|
Store_field(op_info_val, 7, Val_int(insn[j-1].detail->x86.sib_index)); |
|
|
|
Store_field(op_info_val, 8, Val_int(insn[j-1].detail->x86.sib_scale)); |
|
|
|
Store_field(op_info_val, 9, Val_int(insn[j-1].detail->x86.sib_base)); |
|
|
|
Store_field(op_info_val, 10, Val_int(insn[j-1].detail->x86.sse_cc)); |
|
Store_field(op_info_val, 11, Val_int(insn[j-1].detail->x86.avx_cc)); |
|
Store_field(op_info_val, 12, Val_int(insn[j-1].detail->x86.avx_sae)); |
|
Store_field(op_info_val, 13, Val_int(insn[j-1].detail->x86.avx_rm)); |
|
|
|
lcount = insn[j-1].detail->x86.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
switch(insn[j-1].detail->x86.operands[i].type) { |
|
case X86_OP_REG: |
|
tmp = caml_alloc(4, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->x86.operands[i].reg)); |
|
break; |
|
case X86_OP_IMM: |
|
tmp = caml_alloc(4, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->x86.operands[i].imm)); |
|
break; |
|
case X86_OP_FP: |
|
tmp = caml_alloc(4, 3); |
|
Store_field(tmp, 0, caml_copy_double(insn[j-1].detail->x86.operands[i].fp)); |
|
break; |
|
case X86_OP_MEM: |
|
tmp = caml_alloc(4, 4); |
|
tmp2 = caml_alloc(5, 0); |
|
Store_field(tmp2, 0, Val_int(insn[j-1].detail->x86.operands[i].mem.segment)); |
|
Store_field(tmp2, 1, Val_int(insn[j-1].detail->x86.operands[i].mem.base)); |
|
Store_field(tmp2, 2, Val_int(insn[j-1].detail->x86.operands[i].mem.index)); |
|
Store_field(tmp2, 3, Val_int(insn[j-1].detail->x86.operands[i].mem.scale)); |
|
Store_field(tmp2, 4, Val_int(insn[j-1].detail->x86.operands[i].mem.disp)); |
|
|
|
Store_field(tmp, 0, tmp2); |
|
break; |
|
default: |
|
break; |
|
} |
|
Store_field(tmp, 1, Val_int(insn[j-1].detail->x86.operands[i].size)); |
|
Store_field(tmp, 2, Val_int(insn[j-1].detail->x86.operands[i].avx_bcast)); |
|
Store_field(tmp, 3, Val_int(insn[j-1].detail->x86.operands[i].avx_zero_opmask)); |
|
tmp2 = caml_alloc(1, 0); |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
Store_field(op_info_val, 14, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
break; |
|
|
|
case CS_ARCH_PPC: |
|
arch_info = caml_alloc(1, 4); |
|
|
|
op_info_val = caml_alloc(4, 0); |
|
|
|
Store_field(op_info_val, 0, Val_int(insn[j-1].detail->ppc.bc)); |
|
Store_field(op_info_val, 1, Val_int(insn[j-1].detail->ppc.bh)); |
|
Store_field(op_info_val, 2, Val_bool(insn[j-1].detail->ppc.update_cr0)); |
|
|
|
lcount = insn[j-1].detail->ppc.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(1, 0); |
|
switch(insn[j-1].detail->ppc.operands[i].type) { |
|
case PPC_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->ppc.operands[i].reg)); |
|
break; |
|
case PPC_OP_IMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->ppc.operands[i].imm)); |
|
break; |
|
case PPC_OP_MEM: |
|
tmp = caml_alloc(1, 3); |
|
tmp3 = caml_alloc(2, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->ppc.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->ppc.operands[i].mem.disp)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
case PPC_OP_CRX: |
|
tmp = caml_alloc(1, 4); |
|
tmp3 = caml_alloc(3, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->ppc.operands[i].crx.scale)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->ppc.operands[i].crx.reg)); |
|
Store_field(tmp3, 2, Val_int(insn[j-1].detail->ppc.operands[i].crx.cond)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
default: break; |
|
} |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 3, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
|
|
case CS_ARCH_SPARC: |
|
arch_info = caml_alloc(1, 5); |
|
|
|
op_info_val = caml_alloc(3, 0); |
|
|
|
Store_field(op_info_val, 0, Val_int(insn[j-1].detail->sparc.cc)); |
|
Store_field(op_info_val, 1, Val_int(insn[j-1].detail->sparc.hint)); |
|
|
|
lcount = insn[j-1].detail->sparc.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(1, 0); |
|
switch(insn[j-1].detail->sparc.operands[i].type) { |
|
case SPARC_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->sparc.operands[i].reg)); |
|
break; |
|
case SPARC_OP_IMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->sparc.operands[i].imm)); |
|
break; |
|
case SPARC_OP_MEM: |
|
tmp = caml_alloc(1, 3); |
|
tmp3 = caml_alloc(3, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->sparc.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->sparc.operands[i].mem.index)); |
|
Store_field(tmp3, 2, Val_int(insn[j-1].detail->sparc.operands[i].mem.disp)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
default: break; |
|
} |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 2, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
|
|
case CS_ARCH_SYSZ: |
|
arch_info = caml_alloc(1, 6); |
|
|
|
op_info_val = caml_alloc(2, 0); |
|
|
|
Store_field(op_info_val, 0, Val_int(insn[j-1].detail->sysz.cc)); |
|
|
|
lcount = insn[j-1].detail->sysz.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(1, 0); |
|
switch(insn[j-1].detail->sysz.operands[i].type) { |
|
case SYSZ_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->sysz.operands[i].reg)); |
|
break; |
|
case SYSZ_OP_ACREG: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->sysz.operands[i].reg)); |
|
break; |
|
case SYSZ_OP_IMM: |
|
tmp = caml_alloc(1, 3); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->sysz.operands[i].imm)); |
|
break; |
|
case SYSZ_OP_MEM: |
|
tmp = caml_alloc(1, 4); |
|
tmp3 = caml_alloc(4, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->sysz.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->sysz.operands[i].mem.index)); |
|
Store_field(tmp3, 2, caml_copy_int64(insn[j-1].detail->sysz.operands[i].mem.length)); |
|
Store_field(tmp3, 3, caml_copy_int64(insn[j-1].detail->sysz.operands[i].mem.disp)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
default: break; |
|
} |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 1, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
|
|
case CS_ARCH_XCORE: |
|
arch_info = caml_alloc(1, 7); |
|
|
|
op_info_val = caml_alloc(1, 0); |
|
|
|
lcount = insn[j-1].detail->xcore.op_count; |
|
if (lcount > 0) { |
|
array = caml_alloc(lcount, 0); |
|
for (i = 0; i < lcount; i++) { |
|
tmp2 = caml_alloc(1, 0); |
|
switch(insn[j-1].detail->xcore.operands[i].type) { |
|
case XCORE_OP_REG: |
|
tmp = caml_alloc(1, 1); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->xcore.operands[i].reg)); |
|
break; |
|
case XCORE_OP_IMM: |
|
tmp = caml_alloc(1, 2); |
|
Store_field(tmp, 0, Val_int(insn[j-1].detail->xcore.operands[i].imm)); |
|
break; |
|
case XCORE_OP_MEM: |
|
tmp = caml_alloc(1, 3); |
|
tmp3 = caml_alloc(4, 0); |
|
Store_field(tmp3, 0, Val_int(insn[j-1].detail->xcore.operands[i].mem.base)); |
|
Store_field(tmp3, 1, Val_int(insn[j-1].detail->xcore.operands[i].mem.index)); |
|
Store_field(tmp3, 2, caml_copy_int64(insn[j-1].detail->xcore.operands[i].mem.disp)); |
|
Store_field(tmp3, 3, caml_copy_int64(insn[j-1].detail->xcore.operands[i].mem.direct)); |
|
Store_field(tmp, 0, tmp3); |
|
break; |
|
default: break; |
|
} |
|
Store_field(tmp2, 0, tmp); |
|
Store_field(array, i, tmp2); |
|
} |
|
} else // empty array |
|
array = Atom(0); |
|
|
|
Store_field(op_info_val, 0, array); |
|
|
|
// finally, insert this into arch_info |
|
Store_field(arch_info, 0, op_info_val); |
|
|
|
Store_field(rec_insn, 9, arch_info); |
|
|
|
break; |
|
|
|
default: break; |
|
} |
|
} |
|
|
|
Store_field(cons, 0, rec_insn); // head |
|
Store_field(cons, 1, list); // tail |
|
list = cons; |
|
} |
|
cs_free(insn, count); |
|
} |
|
|
|
// do not free the handle here |
|
//cs_close(&handle); |
|
CAMLreturn(list); |
|
} |
|
|
|
CAMLprim value ocaml_cs_disasm(value _arch, value _mode, value _code, value _addr, value _count) |
|
{ |
|
CAMLparam5(_arch, _mode, _code, _addr, _count); |
|
CAMLlocal1(head); |
|
csh handle; |
|
cs_arch arch; |
|
cs_mode mode = 0; |
|
const uint8_t *code; |
|
uint64_t addr; |
|
size_t count, code_len; |
|
|
|
switch (Int_val(_arch)) { |
|
case 0: |
|
arch = CS_ARCH_ARM; |
|
break; |
|
case 1: |
|
arch = CS_ARCH_ARM64; |
|
break; |
|
case 2: |
|
arch = CS_ARCH_MIPS; |
|
break; |
|
case 3: |
|
arch = CS_ARCH_X86; |
|
break; |
|
case 4: |
|
arch = CS_ARCH_PPC; |
|
break; |
|
case 5: |
|
arch = CS_ARCH_SPARC; |
|
break; |
|
case 6: |
|
arch = CS_ARCH_SYSZ; |
|
break; |
|
case 7: |
|
arch = CS_ARCH_XCORE; |
|
break; |
|
default: |
|
caml_invalid_argument("Invalid arch"); |
|
return Val_emptylist; |
|
} |
|
|
|
while (_mode != Val_emptylist) { |
|
head = Field(_mode, 0); /* accessing the head */ |
|
switch (Int_val(head)) { |
|
case 0: |
|
mode |= CS_MODE_LITTLE_ENDIAN; |
|
break; |
|
case 1: |
|
mode |= CS_MODE_ARM; |
|
break; |
|
case 2: |
|
mode |= CS_MODE_16; |
|
break; |
|
case 3: |
|
mode |= CS_MODE_32; |
|
break; |
|
case 4: |
|
mode |= CS_MODE_64; |
|
break; |
|
case 5: |
|
mode |= CS_MODE_THUMB; |
|
break; |
|
case 6: |
|
mode |= CS_MODE_MCLASS; |
|
break; |
|
case 7: |
|
mode |= CS_MODE_V8; |
|
break; |
|
case 8: |
|
mode |= CS_MODE_MICRO; |
|
break; |
|
case 9: |
|
mode |= CS_MODE_MIPS3; |
|
break; |
|
case 10: |
|
mode |= CS_MODE_MIPS32R6; |
|
break; |
|
case 11: |
|
mode |= CS_MODE_MIPSGP64; |
|
break; |
|
case 12: |
|
mode |= CS_MODE_V9; |
|
break; |
|
case 13: |
|
mode |= CS_MODE_BIG_ENDIAN; |
|
break; |
|
case 14: |
|
mode |= CS_MODE_MIPS32; |
|
break; |
|
case 15: |
|
mode |= CS_MODE_MIPS64; |
|
break; |
|
default: |
|
caml_invalid_argument("Invalid mode"); |
|
return Val_emptylist; |
|
} |
|
_mode = Field(_mode, 1); /* point to the tail for next loop */ |
|
} |
|
|
|
cs_err ret = cs_open(arch, mode, &handle); |
|
if (ret != CS_ERR_OK) { |
|
return Val_emptylist; |
|
} |
|
|
|
code = (uint8_t *)String_val(_code); |
|
code_len = caml_string_length(_code); |
|
addr = Int64_val(_addr); |
|
count = Int64_val(_count); |
|
|
|
CAMLreturn(_cs_disasm(arch, handle, code, code_len, addr, count)); |
|
} |
|
|
|
CAMLprim value ocaml_cs_disasm_internal(value _arch, value _handle, value _code, value _addr, value _count) |
|
{ |
|
CAMLparam5(_arch, _handle, _code, _addr, _count); |
|
csh handle; |
|
cs_arch arch; |
|
const uint8_t *code; |
|
uint64_t addr, count, code_len; |
|
|
|
handle = Int64_val(_handle); |
|
|
|
arch = Int_val(_arch); |
|
code = (uint8_t *)String_val(_code); |
|
code_len = caml_string_length(_code); |
|
addr = Int64_val(_addr); |
|
count = Int64_val(_count); |
|
|
|
CAMLreturn(_cs_disasm(arch, handle, code, code_len, addr, count)); |
|
} |
|
|
|
CAMLprim value ocaml_open(value _arch, value _mode) |
|
{ |
|
CAMLparam2(_arch, _mode); |
|
CAMLlocal2(list, head); |
|
csh handle; |
|
cs_arch arch; |
|
cs_mode mode = 0; |
|
|
|
list = Val_emptylist; |
|
|
|
switch (Int_val(_arch)) { |
|
case 0: |
|
arch = CS_ARCH_ARM; |
|
break; |
|
case 1: |
|
arch = CS_ARCH_ARM64; |
|
break; |
|
case 2: |
|
arch = CS_ARCH_MIPS; |
|
break; |
|
case 3: |
|
arch = CS_ARCH_X86; |
|
break; |
|
case 4: |
|
arch = CS_ARCH_PPC; |
|
break; |
|
case 5: |
|
arch = CS_ARCH_SPARC; |
|
break; |
|
case 6: |
|
arch = CS_ARCH_SYSZ; |
|
break; |
|
case 7: |
|
arch = CS_ARCH_XCORE; |
|
break; |
|
default: |
|
caml_invalid_argument("Invalid arch"); |
|
return Val_emptylist; |
|
} |
|
|
|
|
|
while (_mode != Val_emptylist) { |
|
head = Field(_mode, 0); /* accessing the head */ |
|
switch (Int_val(head)) { |
|
case 0: |
|
mode |= CS_MODE_LITTLE_ENDIAN; |
|
break; |
|
case 1: |
|
mode |= CS_MODE_ARM; |
|
break; |
|
case 2: |
|
mode |= CS_MODE_16; |
|
break; |
|
case 3: |
|
mode |= CS_MODE_32; |
|
break; |
|
case 4: |
|
mode |= CS_MODE_64; |
|
break; |
|
case 5: |
|
mode |= CS_MODE_THUMB; |
|
break; |
|
case 6: |
|
mode |= CS_MODE_MCLASS; |
|
break; |
|
case 7: |
|
mode |= CS_MODE_V8; |
|
break; |
|
case 8: |
|
mode |= CS_MODE_MICRO; |
|
break; |
|
case 9: |
|
mode |= CS_MODE_MIPS3; |
|
break; |
|
case 10: |
|
mode |= CS_MODE_MIPS32R6; |
|
break; |
|
case 11: |
|
mode |= CS_MODE_MIPSGP64; |
|
break; |
|
case 12: |
|
mode |= CS_MODE_V9; |
|
break; |
|
case 13: |
|
mode |= CS_MODE_BIG_ENDIAN; |
|
break; |
|
case 14: |
|
mode |= CS_MODE_MIPS32; |
|
break; |
|
case 15: |
|
mode |= CS_MODE_MIPS64; |
|
break; |
|
default: |
|
caml_invalid_argument("Invalid mode"); |
|
return Val_emptylist; |
|
} |
|
_mode = Field(_mode, 1); /* point to the tail for next loop */ |
|
} |
|
|
|
if (cs_open(arch, mode, &handle) != 0) |
|
CAMLreturn(Val_int(0)); |
|
|
|
CAMLlocal1(result); |
|
result = caml_alloc(1, 0); |
|
Store_field(result, 0, caml_copy_int64(handle)); |
|
CAMLreturn(result); |
|
} |
|
|
|
CAMLprim value ocaml_option(value _handle, value _opt, value _value) |
|
{ |
|
CAMLparam3(_handle, _opt, _value); |
|
cs_opt_type opt; |
|
int err; |
|
|
|
switch (Int_val(_opt)) { |
|
case 0: |
|
opt = CS_OPT_SYNTAX; |
|
break; |
|
case 1: |
|
opt = CS_OPT_DETAIL; |
|
break; |
|
case 2: |
|
opt = CS_OPT_MODE; |
|
break; |
|
case 3: |
|
opt = CS_OPT_MEM; |
|
break; |
|
case 4: |
|
opt = CS_OPT_SKIPDATA; |
|
break; |
|
case 5: |
|
opt = CS_OPT_SKIPDATA_SETUP; |
|
break; |
|
default: |
|
caml_invalid_argument("Invalid option"); |
|
CAMLreturn(Val_int(CS_ERR_OPTION)); |
|
} |
|
|
|
err = cs_option(Int64_val(_handle), opt, Int64_val(_value)); |
|
|
|
CAMLreturn(Val_int(err)); |
|
} |
|
|
|
CAMLprim value ocaml_register_name(value _handle, value _reg) |
|
{ |
|
const char *name = cs_reg_name(Int64_val(_handle), Int_val(_reg)); |
|
if (!name) { |
|
caml_invalid_argument("invalid reg_id"); |
|
name = "invalid"; |
|
} |
|
|
|
return caml_copy_string(name); |
|
} |
|
|
|
CAMLprim value ocaml_instruction_name(value _handle, value _insn) |
|
{ |
|
const char *name = cs_insn_name(Int64_val(_handle), Int_val(_insn)); |
|
if (!name) { |
|
caml_invalid_argument("invalid insn_id"); |
|
name = "invalid"; |
|
} |
|
|
|
return caml_copy_string(name); |
|
} |
|
|
|
CAMLprim value ocaml_group_name(value _handle, value _insn) |
|
{ |
|
const char *name = cs_group_name(Int64_val(_handle), Int_val(_insn)); |
|
if (!name) { |
|
caml_invalid_argument("invalid insn_id"); |
|
name = "invalid"; |
|
} |
|
|
|
return caml_copy_string(name); |
|
} |
|
|
|
CAMLprim value ocaml_version(void) |
|
{ |
|
int version = cs_version(NULL, NULL); |
|
return Val_int(version); |
|
} |
|
|
|
CAMLprim value ocaml_close(value _handle) |
|
{ |
|
CAMLparam1(_handle); |
|
csh h; |
|
|
|
h = Int64_val(_handle); |
|
|
|
CAMLreturn(Val_int(cs_close(&h))); |
|
}
|
|
|