802798ce3c
git-subtree-dir: external/capstone git-subtree-split: e46f64fadb351e9ecd05264fab26f2772feb0994
2132 lines
42 KiB
C
2132 lines
42 KiB
C
/* 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 "capstone/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(5, 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(
|
|
tmp2, 4,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->arm
|
|
.operands[i]
|
|
.access));
|
|
Store_field(
|
|
tmp2, 5,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->arm
|
|
.operands[i]
|
|
.neon_lane));
|
|
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,
|
|
tmp3);
|
|
Store_field(
|
|
tmp2, 3,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->arm64
|
|
.operands[i]
|
|
.ext));
|
|
Store_field(tmp2, 4,
|
|
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(17, 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
|
|
.xop_cc));
|
|
Store_field(op_info_val, 11,
|
|
Val_int(insn[j - 1]
|
|
.detail->x86
|
|
.sse_cc));
|
|
Store_field(op_info_val, 12,
|
|
Val_int(insn[j - 1]
|
|
.detail->x86
|
|
.avx_cc));
|
|
Store_field(op_info_val, 13,
|
|
Val_int(insn[j - 1]
|
|
.detail->x86
|
|
.avx_sae));
|
|
Store_field(op_info_val, 14,
|
|
Val_int(insn[j - 1]
|
|
.detail->x86
|
|
.avx_rm));
|
|
Store_field(op_info_val, 15,
|
|
Val_int(insn[j - 1]
|
|
.detail->x86
|
|
.eflags));
|
|
|
|
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(
|
|
1, 1);
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.reg));
|
|
break;
|
|
case X86_OP_IMM:
|
|
tmp = caml_alloc(
|
|
1, 2);
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.imm));
|
|
break;
|
|
case X86_OP_MEM:
|
|
tmp = caml_alloc(
|
|
1, 3);
|
|
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:
|
|
tmp = caml_alloc(
|
|
1,
|
|
0); // X86_OP_INVALID
|
|
break;
|
|
}
|
|
|
|
tmp2 = caml_alloc(5, 0);
|
|
Store_field(tmp2, 0,
|
|
tmp);
|
|
Store_field(
|
|
tmp2, 1,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.size));
|
|
Store_field(
|
|
tmp2, 2,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.access));
|
|
Store_field(
|
|
tmp2, 3,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.avx_bcast));
|
|
Store_field(
|
|
tmp2, 4,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->x86
|
|
.operands[i]
|
|
.avx_zero_opmask));
|
|
Store_field(array, i,
|
|
tmp2);
|
|
}
|
|
} else // empty array
|
|
array = Atom(0);
|
|
Store_field(op_info_val, 16, 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;
|
|
|
|
case CS_ARCH_M680X:
|
|
arch_info = caml_alloc(1, 8);
|
|
|
|
op_info_val = caml_alloc(
|
|
2, 0); // struct cs_m680x
|
|
Store_field(
|
|
op_info_val, 0,
|
|
Val_int(insn[j - 1]
|
|
.detail->m680x
|
|
.flags));
|
|
|
|
lcount =
|
|
insn[j - 1]
|
|
.detail->m680x.op_count;
|
|
if (lcount > 0) {
|
|
array = caml_alloc(lcount, 0);
|
|
for (i = 0; i < lcount; i++) {
|
|
tmp2 = caml_alloc(
|
|
3,
|
|
0); // m680x_op
|
|
switch (insn[j - 1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.type) {
|
|
case M680X_OP_IMMEDIATE:
|
|
tmp = caml_alloc(
|
|
1,
|
|
1); // imm
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.imm));
|
|
break;
|
|
case M680X_OP_REGISTER:
|
|
tmp = caml_alloc(
|
|
1,
|
|
2); // reg
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.reg));
|
|
break;
|
|
case M680X_OP_INDEXED:
|
|
tmp = caml_alloc(
|
|
1, 3);
|
|
tmp3 = caml_alloc(
|
|
7,
|
|
0); // m680x_op_idx
|
|
Store_field(
|
|
tmp3, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.base_reg));
|
|
Store_field(
|
|
tmp3, 1,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.offset_reg));
|
|
Store_field(
|
|
tmp3, 2,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.offset));
|
|
Store_field(
|
|
tmp3, 3,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.offset_addr));
|
|
Store_field(
|
|
tmp3, 4,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.offset_bits));
|
|
Store_field(
|
|
tmp3, 5,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.inc_dec));
|
|
Store_field(
|
|
tmp3, 6,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.idx
|
|
.flags));
|
|
Store_field(
|
|
tmp, 0,
|
|
tmp3);
|
|
break;
|
|
case M680X_OP_RELATIVE:
|
|
tmp = caml_alloc(
|
|
1, 4);
|
|
tmp3 = caml_alloc(
|
|
2,
|
|
0); // m680x_op_rel
|
|
Store_field(
|
|
tmp3, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.rel
|
|
.address));
|
|
Store_field(
|
|
tmp3, 1,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.rel
|
|
.offset));
|
|
Store_field(
|
|
tmp, 0,
|
|
tmp3);
|
|
break;
|
|
case M680X_OP_EXTENDED:
|
|
tmp = caml_alloc(
|
|
1, 5);
|
|
tmp3 = caml_alloc(
|
|
2,
|
|
0); // m680x_op_ext
|
|
Store_field(
|
|
tmp3, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.ext
|
|
.address));
|
|
Store_field(
|
|
tmp3, 1,
|
|
Val_bool(
|
|
insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.ext
|
|
.indirect));
|
|
Store_field(
|
|
tmp, 0,
|
|
tmp3);
|
|
break;
|
|
case M680X_OP_DIRECT:
|
|
tmp = caml_alloc(
|
|
1,
|
|
6); // direct_addr
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.direct_addr));
|
|
break;
|
|
case M680X_OP_CONSTANT:
|
|
tmp = caml_alloc(
|
|
1,
|
|
7); // const_val
|
|
Store_field(
|
|
tmp, 0,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.const_val));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Store_field(
|
|
tmp2, 0,
|
|
tmp); // add union
|
|
Store_field(
|
|
tmp2, 1,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.size));
|
|
Store_field(
|
|
tmp2, 2,
|
|
Val_int(insn[j -
|
|
1]
|
|
.detail
|
|
->m680x
|
|
.operands[i]
|
|
.access));
|
|
Store_field(
|
|
array, i,
|
|
tmp2); // add operand to operand array
|
|
}
|
|
} else // empty list
|
|
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;
|
|
|
|
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;
|
|
case 8:
|
|
arch = CS_ARCH_M68K;
|
|
break;
|
|
case 9:
|
|
arch = CS_ARCH_TMS320C64X;
|
|
break;
|
|
case 10:
|
|
arch = CS_ARCH_M680X;
|
|
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_MIPS2;
|
|
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;
|
|
case 16:
|
|
mode |= CS_MODE_QPX;
|
|
break;
|
|
case 17:
|
|
mode |= CS_MODE_M680X_6301;
|
|
break;
|
|
case 18:
|
|
mode |= CS_MODE_M680X_6309;
|
|
break;
|
|
case 19:
|
|
mode |= CS_MODE_M680X_6800;
|
|
break;
|
|
case 20:
|
|
mode |= CS_MODE_M680X_6801;
|
|
break;
|
|
case 21:
|
|
mode |= CS_MODE_M680X_6805;
|
|
break;
|
|
case 22:
|
|
mode |= CS_MODE_M680X_6808;
|
|
break;
|
|
case 23:
|
|
mode |= CS_MODE_M680X_6809;
|
|
break;
|
|
case 24:
|
|
mode |= CS_MODE_M680X_6811;
|
|
break;
|
|
case 25:
|
|
mode |= CS_MODE_M680X_CPU12;
|
|
break;
|
|
case 26:
|
|
mode |= CS_MODE_M680X_HCS08;
|
|
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;
|
|
case 8:
|
|
arch = CS_ARCH_M68K;
|
|
break;
|
|
case 9:
|
|
arch = CS_ARCH_TMS320C64X;
|
|
break;
|
|
case 10:
|
|
arch = CS_ARCH_M680X;
|
|
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_MIPS2;
|
|
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;
|
|
case 16:
|
|
mode |= CS_MODE_QPX;
|
|
break;
|
|
case 17:
|
|
mode |= CS_MODE_M680X_6301;
|
|
break;
|
|
case 18:
|
|
mode |= CS_MODE_M680X_6309;
|
|
break;
|
|
case 19:
|
|
mode |= CS_MODE_M680X_6800;
|
|
break;
|
|
case 20:
|
|
mode |= CS_MODE_M680X_6801;
|
|
break;
|
|
case 21:
|
|
mode |= CS_MODE_M680X_6805;
|
|
break;
|
|
case 22:
|
|
mode |= CS_MODE_M680X_6808;
|
|
break;
|
|
case 23:
|
|
mode |= CS_MODE_M680X_6809;
|
|
break;
|
|
case 24:
|
|
mode |= CS_MODE_M680X_6811;
|
|
break;
|
|
case 25:
|
|
mode |= CS_MODE_M680X_CPU12;
|
|
break;
|
|
case 26:
|
|
mode |= CS_MODE_M680X_HCS08;
|
|
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)));
|
|
}
|