mirror of
https://github.com/capstone-engine/capstone.git
synced 2025-03-04 04:17:46 +00:00
Add new API and start to provide access information for instruction operands
- New API cs_regs_access() that provide registers being read & modified by instruction - New field cs_x86_op.access provides access info (READ, WRITE) for each operand - New field cs_x86.eflags provides EFLAGS affected by instruction - Extend cs_detail.{regs_read, regs_write} from uint8_t to uint16_t type
This commit is contained in:
parent
bb171fa861
commit
efffe787d1
10
Makefile
10
Makefile
@ -86,6 +86,7 @@ DEP_ARM += arch/ARM/ARMGenDisassemblerTables.inc
|
||||
DEP_ARM += arch/ARM/ARMGenInstrInfo.inc
|
||||
DEP_ARM += arch/ARM/ARMGenRegisterInfo.inc
|
||||
DEP_ARM += arch/ARM/ARMGenSubtargetInfo.inc
|
||||
DEP_ARM += arch/ARM/ARMMappingInsn.inc
|
||||
|
||||
LIBOBJ_ARM =
|
||||
ifneq (,$(findstring arm,$(CAPSTONE_ARCHS)))
|
||||
@ -102,6 +103,7 @@ DEP_ARM64 += arch/AArch64/AArch64GenInstrInfo.inc
|
||||
DEP_ARM64 += arch/AArch64/AArch64GenSubtargetInfo.inc
|
||||
DEP_ARM64 += arch/AArch64/AArch64GenDisassemblerTables.inc
|
||||
DEP_ARM64 += arch/AArch64/AArch64GenRegisterInfo.inc
|
||||
DEP_ARM64 += arch/AArch64/AArch64MappingInsn.inc
|
||||
|
||||
LIBOBJ_ARM64 =
|
||||
ifneq (,$(findstring aarch64,$(CAPSTONE_ARCHS)))
|
||||
@ -120,6 +122,7 @@ DEP_MIPS += arch/Mips/MipsGenDisassemblerTables.inc
|
||||
DEP_MIPS += arch/Mips/MipsGenInstrInfo.inc
|
||||
DEP_MIPS += arch/Mips/MipsGenRegisterInfo.inc
|
||||
DEP_MIPS += arch/Mips/MipsGenSubtargetInfo.inc
|
||||
DEP_MIPS += arch/Mips/MipsMappingInsn.inc
|
||||
|
||||
LIBOBJ_MIPS =
|
||||
ifneq (,$(findstring mips,$(CAPSTONE_ARCHS)))
|
||||
@ -137,6 +140,7 @@ DEP_PPC += arch/PowerPC/PPCGenInstrInfo.inc
|
||||
DEP_PPC += arch/PowerPC/PPCGenSubtargetInfo.inc
|
||||
DEP_PPC += arch/PowerPC/PPCGenDisassemblerTables.inc
|
||||
DEP_PPC += arch/PowerPC/PPCGenRegisterInfo.inc
|
||||
DEP_PPC += arch/PowerPC/PPCMappingInsn.inc
|
||||
|
||||
LIBOBJ_PPC =
|
||||
ifneq (,$(findstring powerpc,$(CAPSTONE_ARCHS)))
|
||||
@ -154,6 +158,7 @@ DEP_SPARC += arch/Sparc/SparcGenInstrInfo.inc
|
||||
DEP_SPARC += arch/Sparc/SparcGenSubtargetInfo.inc
|
||||
DEP_SPARC += arch/Sparc/SparcGenDisassemblerTables.inc
|
||||
DEP_SPARC += arch/Sparc/SparcGenRegisterInfo.inc
|
||||
DEP_SPARC += arch/Sparc/SparcMappingInsn.inc
|
||||
|
||||
LIBOBJ_SPARC =
|
||||
ifneq (,$(findstring sparc,$(CAPSTONE_ARCHS)))
|
||||
@ -171,6 +176,7 @@ DEP_SYSZ += arch/SystemZ/SystemZGenInstrInfo.inc
|
||||
DEP_SYSZ += arch/SystemZ/SystemZGenSubtargetInfo.inc
|
||||
DEP_SYSZ += arch/SystemZ/SystemZGenDisassemblerTables.inc
|
||||
DEP_SYSZ += arch/SystemZ/SystemZGenRegisterInfo.inc
|
||||
DEP_SYSZ += arch/SystemZ/SystemZMappingInsn.inc
|
||||
|
||||
LIBOBJ_SYSZ =
|
||||
ifneq (,$(findstring systemz,$(CAPSTONE_ARCHS)))
|
||||
@ -196,6 +202,9 @@ DEP_X86 += arch/X86/X86GenAsmWriter1$(X86_REDUCE).inc
|
||||
DEP_X86 += arch/X86/X86GenDisassemblerTables$(X86_REDUCE).inc
|
||||
DEP_X86 += arch/X86/X86GenInstrInfo$(X86_REDUCE).inc
|
||||
DEP_X86 += arch/X86/X86GenRegisterInfo.inc
|
||||
DEP_X86 += arch/X86/X86MappingInsn.inc
|
||||
DEP_X86 += arch/X86/X86MappingInsn_reduce.inc
|
||||
DEP_X86 += arch/X86/X86MappingInsnOp.inc
|
||||
|
||||
LIBOBJ_X86 =
|
||||
ifneq (,$(findstring x86,$(CAPSTONE_ARCHS)))
|
||||
@ -219,6 +228,7 @@ DEP_XCORE += arch/XCore/XCoreGenAsmWriter.inc
|
||||
DEP_XCORE += arch/XCore/XCoreGenInstrInfo.inc
|
||||
DEP_XCORE += arch/XCore/XCoreGenDisassemblerTables.inc
|
||||
DEP_XCORE += arch/XCore/XCoreGenRegisterInfo.inc
|
||||
DEP_XCORE += arch/XCore/XCoreMappingInsn.inc
|
||||
|
||||
LIBOBJ_XCORE =
|
||||
ifneq (,$(findstring xcore,$(CAPSTONE_ARCHS)))
|
||||
|
@ -329,7 +329,7 @@ void AArch64_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
insn->detail->arm64.update_flags = cs_reg_write((csh)&handle, insn, ARM64_REG_NZCV);
|
||||
#endif
|
||||
|
@ -296,7 +296,7 @@ void ARM_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
insn->detail->arm.update_flags = cs_reg_write((csh)&handle, insn, ARM_REG_CPSR);
|
||||
|
||||
|
@ -256,7 +256,7 @@ void Mips_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(alias_insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, alias_insns[i].groups, sizeof(alias_insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(alias_insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(alias_insns[i].groups);
|
||||
|
||||
if (alias_insns[i].branch || alias_insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
@ -283,7 +283,7 @@ void Mips_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
|
@ -276,7 +276,7 @@ void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
|
@ -175,7 +175,7 @@ void Sparc_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
|
@ -96,7 +96,7 @@ void SystemZ_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
|
@ -266,12 +266,39 @@ static void _printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
}
|
||||
}
|
||||
|
||||
// convert Intel access info to AT&T access info
|
||||
static void get_op_access(cs_struct *h, unsigned int id, uint8_t *access, uint64_t *eflags)
|
||||
{
|
||||
uint8_t *arr = X86_get_op_access(h, id, eflags);
|
||||
uint8_t count, i;
|
||||
|
||||
// find the non-zero last entry
|
||||
for(count = 0; arr[count]; count++);
|
||||
|
||||
// mark the end of array
|
||||
access[count] = 0;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
// copy in reverse order this access array from Intel syntax -> AT&T syntax
|
||||
count--;
|
||||
for(i = 0; i <= count; i++) {
|
||||
if (arr[count -1] != CS_AC_IGNORE)
|
||||
access[i] = arr[count - i];
|
||||
else
|
||||
access[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
{
|
||||
MCOperand *SegReg;
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
uint8_t access[6];
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -279,6 +306,9 @@ static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
}
|
||||
|
||||
SegReg = MCInst_getOperand(MI, Op+1);
|
||||
@ -306,6 +336,8 @@ static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
static void printDstIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
{
|
||||
if (MI->csh->detail) {
|
||||
uint8_t access[6];
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -313,6 +345,9 @@ static void printDstIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
}
|
||||
|
||||
// DI accesses are always ES-based on non-64bit mode
|
||||
@ -387,6 +422,8 @@ static void printMemOffset(MCInst *MI, unsigned Op, SStream *O)
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
uint8_t access[6];
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -394,6 +431,9 @@ static void printMemOffset(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
}
|
||||
|
||||
// If this has a segment register, print it.
|
||||
@ -506,9 +546,15 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
if (MI->csh->doing_mem) {
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = reg;
|
||||
} else {
|
||||
uint8_t access[6];
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_REG;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].reg = reg;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->csh->regsize_map[reg];
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
}
|
||||
}
|
||||
@ -572,6 +618,8 @@ static void printMemReference(MCInst *MI, unsigned Op, SStream *O)
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
uint8_t access[6];
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -579,6 +627,9 @@ static void printMemReference(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = MCOperand_getReg(IndexReg);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
}
|
||||
|
||||
// If this has a segment register, print it.
|
||||
@ -725,21 +776,31 @@ void X86_ATT_printInst(MCInst *MI, SStream *OS, void *info)
|
||||
// so we have to add the missing register as the first operand
|
||||
reg = X86_insn_reg_att(MCInst_getOpcode(MI));
|
||||
if (reg) {
|
||||
uint8_t access[6];
|
||||
// shift all the ops right to leave 1st slot for this new register op
|
||||
memmove(&(MI->flat_insn->detail->x86.operands[1]), &(MI->flat_insn->detail->x86.operands[0]),
|
||||
sizeof(MI->flat_insn->detail->x86.operands[0]) * (ARR_SIZE(MI->flat_insn->detail->x86.operands) - 1));
|
||||
MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
|
||||
MI->flat_insn->detail->x86.operands[0].reg = reg;
|
||||
MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[0].access = access[0];
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
} else {
|
||||
if (X86_insn_reg_att2(MCInst_getOpcode(MI), ®, ®2)) {
|
||||
uint8_t access[6];
|
||||
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
|
||||
MI->flat_insn->detail->x86.operands[0].type = X86_OP_REG;
|
||||
MI->flat_insn->detail->x86.operands[0].reg = reg;
|
||||
MI->flat_insn->detail->x86.operands[0].size = MI->csh->regsize_map[reg];
|
||||
MI->flat_insn->detail->x86.operands[0].access = access[0];
|
||||
MI->flat_insn->detail->x86.operands[1].type = X86_OP_REG;
|
||||
MI->flat_insn->detail->x86.operands[1].reg = reg2;
|
||||
MI->flat_insn->detail->x86.operands[1].size = MI->csh->regsize_map[reg2];
|
||||
MI->flat_insn->detail->x86.operands[1].access = access[1];
|
||||
MI->flat_insn->detail->x86.op_count = 2;
|
||||
}
|
||||
}
|
||||
|
@ -284,12 +284,38 @@ static void _printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
// convert Intel access info to AT&T access info
|
||||
static void get_op_access(cs_struct *h, unsigned int id, uint8_t *access, uint64_t *eflags)
|
||||
{
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t *arr = X86_get_op_access(h, id, eflags);
|
||||
uint8_t i;
|
||||
|
||||
// copy to access but zero out CS_AC_IGNORE
|
||||
for(i = 0; arr[i]; i++) {
|
||||
if (arr[i] != CS_AC_IGNORE)
|
||||
access[i] = arr[i];
|
||||
else
|
||||
access[i] = 0;
|
||||
}
|
||||
|
||||
// mark the end of array
|
||||
access[i] = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
{
|
||||
MCOperand *SegReg;
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -297,6 +323,11 @@ static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
}
|
||||
|
||||
SegReg = MCInst_getOperand(MI, Op+1);
|
||||
@ -321,6 +352,10 @@ static void printSrcIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
static void printDstIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
{
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -328,6 +363,11 @@ static void printDstIdx(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
}
|
||||
|
||||
// DI accesses are always ES-based on non-64bit mode
|
||||
@ -408,6 +448,10 @@ static void printMemOffset(MCInst *MI, unsigned Op, SStream *O)
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -415,6 +459,11 @@ static void printMemOffset(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = X86_REG_INVALID;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = 1;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
}
|
||||
|
||||
// If this has a segment register, print it.
|
||||
@ -463,8 +512,18 @@ static void printU8Imm(MCInst *MI, unsigned Op, SStream *O)
|
||||
SStream_concat(O, "%u", val);
|
||||
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_IMM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].imm = val;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
}
|
||||
}
|
||||
@ -514,6 +573,10 @@ void X86_Intel_printInst(MCInst *MI, SStream *O, void *Info)
|
||||
|
||||
reg = X86_insn_reg_intel(MCInst_getOpcode(MI));
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
// first op can be embedded in the asm by llvm.
|
||||
// so we have to add the missing register as the first operand
|
||||
if (reg) {
|
||||
@ -536,6 +599,12 @@ void X86_Intel_printInst(MCInst *MI, SStream *O, void *Info)
|
||||
MI->flat_insn->detail->x86.op_count = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[0].access = access[0];
|
||||
MI->flat_insn->detail->x86.operands[1].access = access[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
if (MI->op1_size == 0 && reg)
|
||||
@ -562,6 +631,10 @@ static void printPCRelImm(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
SStream_concat(O, "%"PRIu64, imm);
|
||||
}
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_IMM;
|
||||
// if op_count > 0, then this operand's size is taken from the destination op
|
||||
if (MI->flat_insn->detail->x86.op_count > 0)
|
||||
@ -569,6 +642,12 @@ static void printPCRelImm(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
else
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->imm_size;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].imm = imm;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
}
|
||||
|
||||
@ -588,9 +667,19 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
if (MI->csh->doing_mem) {
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.base = reg;
|
||||
} else {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_REG;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].reg = reg;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->csh->regsize_map[reg];
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
}
|
||||
}
|
||||
@ -647,12 +736,22 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
|
||||
if (MI->csh->doing_mem) {
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = imm;
|
||||
} else {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_IMM;
|
||||
if (MI->flat_insn->detail->x86.op_count > 0)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->flat_insn->detail->x86.operands[0].size;
|
||||
else
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->imm_size;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].imm = imm;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.op_count++;
|
||||
}
|
||||
}
|
||||
@ -673,6 +772,10 @@ static void printMemReference(MCInst *MI, unsigned Op, SStream *O)
|
||||
int reg;
|
||||
|
||||
if (MI->csh->detail) {
|
||||
#ifndef CAPSTONE_DIET
|
||||
uint8_t access[6];
|
||||
#endif
|
||||
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].type = X86_OP_MEM;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].size = MI->x86opsize;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.segment = X86_REG_INVALID;
|
||||
@ -680,6 +783,11 @@ static void printMemReference(MCInst *MI, unsigned Op, SStream *O)
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.index = MCOperand_getReg(IndexReg);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.scale = (int)ScaleVal;
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].mem.disp = 0;
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
get_op_access(MI->csh, MCInst_getOpcode(MI), access, &MI->flat_insn->detail->x86.eflags);
|
||||
MI->flat_insn->detail->x86.operands[MI->flat_insn->detail->x86.op_count].access = access[MI->flat_insn->detail->x86.op_count];
|
||||
#endif
|
||||
}
|
||||
|
||||
// If this has a segment register, print it.
|
||||
|
@ -2338,7 +2338,7 @@ void X86_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
}
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
@ -2970,12 +2970,11 @@ void op_addAvxBroadcast(MCInst *MI, x86_avx_bcast v)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
// map instruction to its characteristics
|
||||
typedef struct insn_op {
|
||||
unsigned int eflags_update; // how this instruction update EFlags
|
||||
cs_ac_type operands[4];
|
||||
uint64_t eflags; // how this instruction update EFLAGS
|
||||
uint8_t access[6];
|
||||
} insn_op;
|
||||
|
||||
static insn_op insn_ops[] = {
|
||||
@ -2984,8 +2983,76 @@ static insn_op insn_ops[] = {
|
||||
{ 0 }
|
||||
},
|
||||
|
||||
#ifdef CAPSTONE_X86_REDUCE
|
||||
#include "X86MappingInsnOp_reduce.inc"
|
||||
#else
|
||||
#include "X86MappingInsnOp.inc"
|
||||
#endif
|
||||
};
|
||||
|
||||
// given internal insn id, return operand access info
|
||||
uint8_t *X86_get_op_access(cs_struct *h, unsigned int id, uint64_t *eflags)
|
||||
{
|
||||
int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
|
||||
if (i != 0) {
|
||||
*eflags = insn_ops[i].eflags;
|
||||
return insn_ops[i].access;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void X86_reg_access(const cs_insn *insn,
|
||||
cs_regs regs_read, uint8_t *regs_read_count,
|
||||
cs_regs regs_write, uint8_t *regs_write_count)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t read_count, write_count;
|
||||
cs_x86 *x86 = &(insn->detail->x86);
|
||||
|
||||
read_count = insn->detail->regs_read_count;
|
||||
write_count = insn->detail->regs_write_count;
|
||||
|
||||
// implicit registers
|
||||
memcpy(regs_read, insn->detail->regs_read, read_count * sizeof(insn->detail->regs_read[0]));
|
||||
memcpy(regs_write, insn->detail->regs_write, write_count * sizeof(insn->detail->regs_write[0]));
|
||||
|
||||
// explicit registers
|
||||
for (i = 0; i < x86->op_count; i++) {
|
||||
cs_x86_op *op = &(x86->operands[i]);
|
||||
switch((int)op->type) {
|
||||
case X86_OP_REG:
|
||||
if (op->access & CS_AC_READ) {
|
||||
regs_read[read_count] = op->reg;
|
||||
read_count++;
|
||||
}
|
||||
if (op->access & CS_AC_WRITE) {
|
||||
regs_write[write_count] = op->reg;
|
||||
write_count++;
|
||||
}
|
||||
break;
|
||||
case X86_OP_MEM:
|
||||
// registers appeared in memory references always being read
|
||||
if (op->mem.segment != X86_REG_INVALID) {
|
||||
regs_read[read_count] = op->mem.segment;
|
||||
read_count++;
|
||||
}
|
||||
if (op->mem.base != X86_REG_INVALID) {
|
||||
regs_read[read_count] = op->mem.base;
|
||||
read_count++;
|
||||
}
|
||||
if (op->mem.index != X86_REG_INVALID) {
|
||||
regs_read[read_count] = op->mem.index;
|
||||
read_count++;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*regs_read_count = read_count;
|
||||
*regs_write_count = write_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -61,4 +61,11 @@ void op_addAvxSae(MCInst *MI);
|
||||
|
||||
void op_addAvxRoundingMode(MCInst *MI, int v);
|
||||
|
||||
// given internal insn id, return operand access info
|
||||
uint8_t *X86_get_op_access(cs_struct *h, unsigned int id, uint64_t *eflags);
|
||||
|
||||
void X86_reg_access(const cs_insn *insn,
|
||||
cs_regs regs_read, uint8_t *regs_read_count,
|
||||
cs_regs regs_write, uint8_t *regs_write_count);
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
6235
arch/X86/X86MappingInsnOp_reduce.inc
Normal file
6235
arch/X86/X86MappingInsnOp_reduce.inc
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,9 @@ static cs_err init(cs_struct *ud)
|
||||
ud->insn_name = X86_insn_name;
|
||||
ud->group_name = X86_group_name;
|
||||
ud->post_printer = NULL;;
|
||||
#ifndef CAPSTONE_DIET
|
||||
ud->reg_access = X86_reg_access;
|
||||
#endif
|
||||
|
||||
if (ud->mode == CS_MODE_64)
|
||||
ud->regsize_map = regsize_map_64;
|
||||
|
@ -101,7 +101,7 @@ void XCore_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
||||
|
||||
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
||||
insn->detail->groups_count = (uint8_t)count_positive(insns[i].groups);
|
||||
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
||||
|
||||
if (insns[i].branch || insns[i].indirect_branch) {
|
||||
// this insn also belongs to JUMP group. add JUMP group
|
||||
|
82
cs.c
82
cs.c
@ -157,7 +157,7 @@ const char *cs_strerror(cs_err code)
|
||||
case CS_ERR_MEM:
|
||||
return "Out of memory (CS_ERR_MEM)";
|
||||
case CS_ERR_ARCH:
|
||||
return "Invalid architecture (CS_ERR_ARCH)";
|
||||
return "Invalid/unsupported architecture(CS_ERR_ARCH)";
|
||||
case CS_ERR_HANDLE:
|
||||
return "Invalid handle (CS_ERR_HANDLE)";
|
||||
case CS_ERR_CSH:
|
||||
@ -774,7 +774,19 @@ const char *cs_group_name(csh ud, unsigned int group)
|
||||
return handle->group_name(ud, group);
|
||||
}
|
||||
|
||||
static bool arr_exist(unsigned char *arr, unsigned char max, unsigned int id)
|
||||
static bool arr_exist8(unsigned char *arr, unsigned char max, unsigned int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (arr[i] == id)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool arr_exist(uint16_t *arr, unsigned char max, unsigned int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -800,17 +812,17 @@ bool cs_insn_group(csh ud, const cs_insn *insn, unsigned int group_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->id) {
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->detail) {
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return arr_exist(insn->detail->groups, insn->detail->groups_count, group_id);
|
||||
return arr_exist8(insn->detail->groups, insn->detail->groups_count, group_id);
|
||||
}
|
||||
|
||||
CAPSTONE_EXPORT
|
||||
@ -827,12 +839,12 @@ bool cs_reg_read(csh ud, const cs_insn *insn, unsigned int reg_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->id) {
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->detail) {
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return false;
|
||||
}
|
||||
@ -854,12 +866,12 @@ bool cs_reg_write(csh ud, const cs_insn *insn, unsigned int reg_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->id) {
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!insn->detail) {
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return false;
|
||||
}
|
||||
@ -882,12 +894,12 @@ int cs_op_count(csh ud, const cs_insn *insn, unsigned int op_type)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!insn->id) {
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!insn->detail) {
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return -1;
|
||||
}
|
||||
@ -959,12 +971,12 @@ int cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!insn->id) {
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!insn->detail) {
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return -1;
|
||||
}
|
||||
@ -1043,3 +1055,47 @@ int cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type,
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
CAPSTONE_EXPORT
|
||||
cs_err cs_regs_access(csh ud, const cs_insn *insn,
|
||||
cs_regs regs_read, uint8_t *regs_read_count,
|
||||
cs_regs regs_write, uint8_t *regs_write_count)
|
||||
{
|
||||
struct cs_struct *handle;
|
||||
|
||||
if (!ud)
|
||||
return -1;
|
||||
|
||||
handle = (struct cs_struct *)(uintptr_t)ud;
|
||||
|
||||
#ifdef CAPSTONE_DIET
|
||||
// This API does not work in DIET mode
|
||||
handle->errnum = CS_ERR_DIET;
|
||||
return CS_ERR_DIET;
|
||||
#else
|
||||
if (!handle->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return CS_ERR_DETAIL;
|
||||
}
|
||||
|
||||
if (!insn->id) {
|
||||
handle->errnum = CS_ERR_SKIPDATA;
|
||||
return CS_ERR_SKIPDATA;
|
||||
}
|
||||
|
||||
if (!insn->detail) {
|
||||
handle->errnum = CS_ERR_DETAIL;
|
||||
return CS_ERR_DETAIL;
|
||||
}
|
||||
|
||||
if (handle->reg_access) {
|
||||
handle->reg_access(insn, regs_read, regs_read_count, regs_write, regs_write_count);
|
||||
} else {
|
||||
// this arch is unsupported yet
|
||||
handle->errnum = CS_ERR_ARCH;
|
||||
return CS_ERR_ARCH;
|
||||
}
|
||||
|
||||
return CS_ERR_OK;
|
||||
#endif
|
||||
}
|
||||
|
@ -24,6 +24,11 @@ typedef void (*GetID_t)(cs_struct *h, cs_insn *insn, unsigned int id);
|
||||
// return register name, given register ID
|
||||
typedef char *(*GetRegisterName_t)(unsigned RegNo);
|
||||
|
||||
// return registers accessed by instruction
|
||||
typedef void (*GetRegisterAccess_t)(const cs_insn *insn,
|
||||
cs_regs regs_read, uint8_t *regs_read_count,
|
||||
cs_regs regs_write, uint8_t *regs_write_count);
|
||||
|
||||
// for ARM only
|
||||
typedef struct ARM_ITStatus {
|
||||
unsigned char ITStates[128]; // FIXME
|
||||
@ -54,6 +59,7 @@ struct cs_struct {
|
||||
uint8_t skipdata_size; // how many bytes to skip
|
||||
cs_opt_skipdata skipdata_setup; // user-defined skipdata setup
|
||||
uint8_t *regsize_map; // map to register size (x86-only for now)
|
||||
GetRegisterAccess_t reg_access;
|
||||
};
|
||||
|
||||
#define MAX_ARCH 8
|
||||
|
@ -146,6 +146,14 @@ typedef enum cs_op_type {
|
||||
CS_OP_FP, // Floating-Point operand.
|
||||
} cs_op_type;
|
||||
|
||||
//> Common instruction operand access types - to be consistent across all architectures.
|
||||
//> It is possible to combine access types, for example: CS_AC_READ | CS_AC_WRITE
|
||||
typedef enum cs_ac_type {
|
||||
CS_AC_INVALID = 0, // Uninitialized/invalid access type.
|
||||
CS_AC_READ = 1 << 0, // Operand read from memory or register.
|
||||
CS_AC_WRITE = 1 << 1, // Operand write to memory or register.
|
||||
} cs_ac_type;
|
||||
|
||||
//> Common instruction groups - to be consistent across all architectures.
|
||||
typedef enum cs_group_type {
|
||||
CS_GRP_INVALID = 0, // uninitialized/invalid group.
|
||||
@ -213,10 +221,10 @@ typedef struct cs_opt_skipdata {
|
||||
|
||||
// NOTE: All information in cs_detail is only available when CS_OPT_DETAIL = CS_OPT_ON
|
||||
typedef struct cs_detail {
|
||||
uint8_t regs_read[12]; // list of implicit registers read by this insn
|
||||
uint16_t regs_read[12]; // list of implicit registers read by this insn
|
||||
uint8_t regs_read_count; // number of implicit registers read by this insn
|
||||
|
||||
uint8_t regs_write[20]; // list of implicit registers modified by this insn
|
||||
uint16_t regs_write[20]; // list of implicit registers modified by this insn
|
||||
uint8_t regs_write_count; // number of implicit registers modified by this insn
|
||||
|
||||
uint8_t groups[8]; // list of group this instruction belong to
|
||||
@ -657,6 +665,31 @@ CAPSTONE_EXPORT
|
||||
int cs_op_index(csh handle, const cs_insn *insn, unsigned int op_type,
|
||||
unsigned int position);
|
||||
|
||||
// Type of array to keep the list of registers
|
||||
typedef uint16_t cs_regs[64];
|
||||
|
||||
/*
|
||||
Retrieve all the registers accessed by an instruction, either explicitly or
|
||||
implicitly.
|
||||
|
||||
WARN: when in 'diet' mode, this API is irrelevant because engine does not
|
||||
store registers.
|
||||
|
||||
@handle: handle returned by cs_open()
|
||||
@insn: disassembled instruction structure returned from cs_disasm() or cs_disasm_iter()
|
||||
@regs_read: on return, this array contains all registers read by instruction.
|
||||
@regs_read_count: number of registers kept inside @regs_read array.
|
||||
@regs_write: on return, this array contains all registers written by instruction.
|
||||
@regs_write_count: number of registers kept inside @regs_write array.
|
||||
|
||||
@return CS_ERR_OK on success, or other value on failure (refer to cs_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
CAPSTONE_EXPORT
|
||||
cs_err cs_regs_access(csh handle, const cs_insn *insn,
|
||||
cs_regs regs_read, uint8_t *regs_read_count,
|
||||
cs_regs regs_write, uint8_t *regs_write_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -69,6 +69,56 @@ typedef enum x86_reg {
|
||||
X86_REG_ENDING // <-- mark the end of the list of registers
|
||||
} x86_reg;
|
||||
|
||||
//> Sub-flags of EFLAGS
|
||||
typedef enum x86_eflags_type {
|
||||
X86_EFLAGS_MODIFY_AF = (uint64_t)1 << 0,
|
||||
X86_EFLAGS_MODIFY_CF = (uint64_t)1 << 1,
|
||||
X86_EFLAGS_MODIFY_SF = (uint64_t)1 << 2,
|
||||
X86_EFLAGS_MODIFY_ZF = (uint64_t)1 << 3,
|
||||
X86_EFLAGS_MODIFY_PF = (uint64_t)1 << 4,
|
||||
X86_EFLAGS_MODIFY_OF = (uint64_t)1 << 5,
|
||||
X86_EFLAGS_MODIFY_TF = (uint64_t)1 << 6,
|
||||
X86_EFLAGS_MODIFY_IF = (uint64_t)1 << 7,
|
||||
X86_EFLAGS_MODIFY_DF = (uint64_t)1 << 8,
|
||||
X86_EFLAGS_MODIFY_NT = (uint64_t)1 << 9,
|
||||
X86_EFLAGS_MODIFY_RF = (uint64_t)1 << 10,
|
||||
X86_EFLAGS_PRIOR_OF = (uint64_t)1 << 11,
|
||||
X86_EFLAGS_PRIOR_SF = (uint64_t)1 << 12,
|
||||
X86_EFLAGS_PRIOR_ZF = (uint64_t)1 << 13,
|
||||
X86_EFLAGS_PRIOR_AF = (uint64_t)1 << 14,
|
||||
X86_EFLAGS_PRIOR_PF = (uint64_t)1 << 15,
|
||||
X86_EFLAGS_PRIOR_CF = (uint64_t)1 << 16,
|
||||
X86_EFLAGS_PRIOR_TF = (uint64_t)1 << 17,
|
||||
X86_EFLAGS_PRIOR_IF = (uint64_t)1 << 18,
|
||||
X86_EFLAGS_PRIOR_DF = (uint64_t)1 << 19,
|
||||
X86_EFLAGS_PRIOR_NT = (uint64_t)1 << 20,
|
||||
X86_EFLAGS_RESET_OF = (uint64_t)1 << 21,
|
||||
X86_EFLAGS_RESET_CF = (uint64_t)1 << 22,
|
||||
X86_EFLAGS_RESET_DF = (uint64_t)1 << 23,
|
||||
X86_EFLAGS_RESET_IF = (uint64_t)1 << 24,
|
||||
X86_EFLAGS_RESET_SF = (uint64_t)1 << 25,
|
||||
X86_EFLAGS_RESET_AF = (uint64_t)1 << 26,
|
||||
X86_EFLAGS_RESET_TF = (uint64_t)1 << 27,
|
||||
X86_EFLAGS_RESET_NT = (uint64_t)1 << 28,
|
||||
X86_EFLAGS_RESET_PF = (uint64_t)1 << 29,
|
||||
X86_EFLAGS_SET_CF = (uint64_t)1 << 30,
|
||||
X86_EFLAGS_SET_DF = (uint64_t)1 << 31,
|
||||
X86_EFLAGS_SET_IF = (uint64_t)1 << 32,
|
||||
X86_EFLAGS_TEST_OF = (uint64_t)1 << 33,
|
||||
X86_EFLAGS_TEST_SF = (uint64_t)1 << 34,
|
||||
X86_EFLAGS_TEST_ZF = (uint64_t)1 << 35,
|
||||
X86_EFLAGS_TEST_PF = (uint64_t)1 << 36,
|
||||
X86_EFLAGS_TEST_CF = (uint64_t)1 << 37,
|
||||
X86_EFLAGS_TEST_NT = (uint64_t)1 << 38,
|
||||
X86_EFLAGS_TEST_DF = (uint64_t)1 << 39,
|
||||
X86_EFLAGS_UNDEFINED_OF = (uint64_t)1 << 40,
|
||||
X86_EFLAGS_UNDEFINED_SF = (uint64_t)1 << 41,
|
||||
X86_EFLAGS_UNDEFINED_ZF = (uint64_t)1 << 42,
|
||||
X86_EFLAGS_UNDEFINED_PF = (uint64_t)1 << 43,
|
||||
X86_EFLAGS_UNDEFINED_AF = (uint64_t)1 << 44,
|
||||
X86_EFLAGS_UNDEFINED_CF = (uint64_t)1 << 45,
|
||||
} x86_eflags_type;
|
||||
|
||||
//> Operand type for instruction's operands
|
||||
typedef enum x86_op_type {
|
||||
X86_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized).
|
||||
@ -200,6 +250,11 @@ typedef struct cs_x86_op {
|
||||
// size of this operand (in bytes).
|
||||
uint8_t size;
|
||||
|
||||
// How is this operand accessed? (READ, WRITE or READ|WRITE)
|
||||
// This field is combined of cs_ac_type.
|
||||
// NOTE: this field is irrelevant if engine is compiled in DIET mode.
|
||||
uint8_t access;
|
||||
|
||||
// AVX broadcast type, or 0 if irrelevant
|
||||
x86_avx_bcast avx_bcast;
|
||||
|
||||
@ -261,6 +316,10 @@ typedef struct cs_x86 {
|
||||
// AVX static rounding mode
|
||||
x86_avx_rm avx_rm;
|
||||
|
||||
// EFLAGS updated by this instruction.
|
||||
// This can be formed from OR combination of X86_EFLAGS_* symbols in x86.h
|
||||
uint64_t eflags;
|
||||
|
||||
// Number of operands of this instruction,
|
||||
// or 0 when instruction has no operand.
|
||||
uint8_t op_count;
|
||||
|
154
tests/test_x86.c
154
tests/test_x86.c
@ -31,10 +31,112 @@ static void print_string_hex(char *comment, unsigned char *str, size_t len)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static char *get_eflag_name(uint64_t flag)
|
||||
{
|
||||
switch(flag) {
|
||||
default:
|
||||
return NULL;
|
||||
case X86_EFLAGS_UNDEFINED_OF:
|
||||
return "UNDEF_OF";
|
||||
case X86_EFLAGS_UNDEFINED_SF:
|
||||
return "UNDEF_SF";
|
||||
case X86_EFLAGS_UNDEFINED_ZF:
|
||||
return "UNDEF_ZF";
|
||||
case X86_EFLAGS_MODIFY_AF:
|
||||
return "MOD_AF";
|
||||
case X86_EFLAGS_UNDEFINED_PF:
|
||||
return "UNDEF_PF";
|
||||
case X86_EFLAGS_MODIFY_CF:
|
||||
return "MOD_CF";
|
||||
case X86_EFLAGS_MODIFY_SF:
|
||||
return "MOD_SF";
|
||||
case X86_EFLAGS_MODIFY_ZF:
|
||||
return "MOD_ZF";
|
||||
case X86_EFLAGS_UNDEFINED_AF:
|
||||
return "UNDEF_AF";
|
||||
case X86_EFLAGS_MODIFY_PF:
|
||||
return "MOD_PF";
|
||||
case X86_EFLAGS_UNDEFINED_CF:
|
||||
return "UNDEF_CF";
|
||||
case X86_EFLAGS_MODIFY_OF:
|
||||
return "MOD_OF";
|
||||
case X86_EFLAGS_RESET_OF:
|
||||
return "RESET_OF";
|
||||
case X86_EFLAGS_RESET_CF:
|
||||
return "RESET_CF";
|
||||
case X86_EFLAGS_RESET_DF:
|
||||
return "RESET_DF";
|
||||
case X86_EFLAGS_RESET_IF:
|
||||
return "RESET_IF";
|
||||
case X86_EFLAGS_TEST_OF:
|
||||
return "TEST_OF";
|
||||
case X86_EFLAGS_TEST_SF:
|
||||
return "TEST_SF";
|
||||
case X86_EFLAGS_TEST_ZF:
|
||||
return "TEST_ZF";
|
||||
case X86_EFLAGS_TEST_PF:
|
||||
return "TEST_PF";
|
||||
case X86_EFLAGS_TEST_CF:
|
||||
return "TEST_CF";
|
||||
case X86_EFLAGS_RESET_SF:
|
||||
return "RESET_SF";
|
||||
case X86_EFLAGS_RESET_AF:
|
||||
return "RESET_AF";
|
||||
case X86_EFLAGS_RESET_TF:
|
||||
return "RESET_TF";
|
||||
case X86_EFLAGS_RESET_NT:
|
||||
return "RESET_NT";
|
||||
case X86_EFLAGS_PRIOR_OF:
|
||||
return "PRIOR_OF";
|
||||
case X86_EFLAGS_PRIOR_SF:
|
||||
return "PRIOR_SF";
|
||||
case X86_EFLAGS_PRIOR_ZF:
|
||||
return "PRIOR_ZF";
|
||||
case X86_EFLAGS_PRIOR_AF:
|
||||
return "PRIOR_AF";
|
||||
case X86_EFLAGS_PRIOR_PF:
|
||||
return "PRIOR_PF";
|
||||
case X86_EFLAGS_PRIOR_CF:
|
||||
return "PRIOR_CF";
|
||||
case X86_EFLAGS_PRIOR_TF:
|
||||
return "PRIOR_TF";
|
||||
case X86_EFLAGS_PRIOR_IF:
|
||||
return "PRIOR_IF";
|
||||
case X86_EFLAGS_PRIOR_DF:
|
||||
return "PRIOR_DF";
|
||||
case X86_EFLAGS_TEST_NT:
|
||||
return "TEST_NT";
|
||||
case X86_EFLAGS_TEST_DF:
|
||||
return "TEST_DF";
|
||||
case X86_EFLAGS_RESET_PF:
|
||||
return "RESET_PF";
|
||||
case X86_EFLAGS_PRIOR_NT:
|
||||
return "PRIOR_NT";
|
||||
case X86_EFLAGS_MODIFY_TF:
|
||||
return "MOD_TF";
|
||||
case X86_EFLAGS_MODIFY_IF:
|
||||
return "MOD_IF";
|
||||
case X86_EFLAGS_MODIFY_DF:
|
||||
return "MOD_DF";
|
||||
case X86_EFLAGS_MODIFY_NT:
|
||||
return "MOD_NT";
|
||||
case X86_EFLAGS_MODIFY_RF:
|
||||
return "MOD_RF";
|
||||
case X86_EFLAGS_SET_CF:
|
||||
return "SET_CF";
|
||||
case X86_EFLAGS_SET_DF:
|
||||
return "SET_DF";
|
||||
case X86_EFLAGS_SET_IF:
|
||||
return "SET_IF";
|
||||
}
|
||||
}
|
||||
|
||||
static void print_insn_detail(csh ud, cs_mode mode, cs_insn *ins)
|
||||
{
|
||||
int count, i;
|
||||
cs_x86 *x86;
|
||||
cs_regs regs_read, regs_write;
|
||||
uint8_t regs_read_count, regs_write_count;
|
||||
|
||||
// detail can be NULL on "data" instruction if SKIPDATA option is turned ON
|
||||
if (ins->detail == NULL)
|
||||
@ -88,6 +190,7 @@ static void print_insn_detail(csh ud, cs_mode mode, cs_insn *ins)
|
||||
printf("\tavx_rm: %u\n", x86->avx_rm);
|
||||
}
|
||||
|
||||
// Print out all immediate operands
|
||||
count = cs_op_count(ud, ins, X86_OP_IMM);
|
||||
if (count) {
|
||||
printf("\timm_count: %u\n", count);
|
||||
@ -99,6 +202,8 @@ static void print_insn_detail(csh ud, cs_mode mode, cs_insn *ins)
|
||||
|
||||
if (x86->op_count)
|
||||
printf("\top_count: %u\n", x86->op_count);
|
||||
|
||||
// Print out all operands
|
||||
for (i = 0; i < x86->op_count; i++) {
|
||||
cs_x86_op *op = &(x86->operands[i]);
|
||||
|
||||
@ -138,6 +243,50 @@ static void print_insn_detail(csh ud, cs_mode mode, cs_insn *ins)
|
||||
printf("\t\toperands[%u].avx_zero_opmask: TRUE\n", i);
|
||||
|
||||
printf("\t\toperands[%u].size: %u\n", i, op->size);
|
||||
|
||||
switch(op->access) {
|
||||
default:
|
||||
break;
|
||||
case CS_AC_READ:
|
||||
printf("\t\toperands[%u].access: READ\n", i);
|
||||
break;
|
||||
case CS_AC_WRITE:
|
||||
printf("\t\toperands[%u].access: WRITE\n", i);
|
||||
break;
|
||||
case CS_AC_READ | CS_AC_WRITE:
|
||||
printf("\t\toperands[%u].access: READ | WRITE\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Print out all registers accessed by this instruction (either implicit or explicit)
|
||||
if (!cs_regs_access(ud, ins,
|
||||
regs_read, ®s_read_count,
|
||||
regs_write, ®s_write_count)) {
|
||||
if (regs_read_count) {
|
||||
printf("\tRegisters read:");
|
||||
for(i = 0; i < regs_read_count; i++) {
|
||||
printf(" %s", cs_reg_name(handle, regs_read[i]));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (regs_write_count) {
|
||||
printf("\tRegisters modified:");
|
||||
for(i = 0; i < regs_write_count; i++) {
|
||||
printf(" %s", cs_reg_name(handle, regs_write[i]));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (x86->eflags) {
|
||||
printf("\tEFLAGS:");
|
||||
for(i = 0; i <=45; i++)
|
||||
if (x86->eflags & (1 << i)) {
|
||||
printf(" %s", get_eflag_name((uint64_t)1 << i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@ -157,8 +306,8 @@ static void test()
|
||||
//#define X86_CODE64 "\xe9\x79\xff\xff\xff" // jmp 0xf7e
|
||||
|
||||
#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
|
||||
//#define X86_CODE16 "\x67\x00\x18"
|
||||
#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6"
|
||||
//#define X86_CODE32 "\x05\x23\x01\x00\x00\x0f\x01\xda"
|
||||
//#define X86_CODE32 "\x0f\xa7\xc0" // xstorerng
|
||||
//#define X86_CODE32 "\x64\xa1\x18\x00\x00\x00" // mov eax, dword ptr fs:[18]
|
||||
//#define X86_CODE32 "\x64\xa3\x00\x00\x00\x00" // mov [fs:0x0], eax
|
||||
@ -170,6 +319,7 @@ static void test()
|
||||
//#define X86_CODE32 "\x24\xb8" // and $0xb8,%al
|
||||
//#define X86_CODE32 "\xf0\x01\xd8" // lock add eax,ebx
|
||||
//#define X86_CODE32 "\xf3\xaa" // rep stosb
|
||||
//#define X86_CODE32 "\x81\xc6\x23\x01\x00\x00"
|
||||
|
||||
struct platform platforms[] = {
|
||||
{
|
||||
@ -231,7 +381,7 @@ static void test()
|
||||
printf("Disasm:\n");
|
||||
|
||||
for (j = 0; j < count; j++) {
|
||||
printf("0x%"PRIx64":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
|
||||
printf("0x%"PRIx64":\t%s\t%s\n\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
|
||||
print_insn_detail(handle, platforms[i].mode, &insn[j]);
|
||||
}
|
||||
printf("0x%"PRIx64":\n", insn[j-1].address + insn[j-1].size);
|
||||
|
13
utils.c
13
utils.c
@ -50,7 +50,18 @@ int name2id(name_map* map, int max, const char *name)
|
||||
|
||||
// count number of positive members in a list.
|
||||
// NOTE: list must be guaranteed to end in 0
|
||||
unsigned int count_positive(unsigned char *list)
|
||||
unsigned int count_positive(uint16_t *list)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
for (c = 0; list[c] > 0; c++);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// count number of positive members in a list.
|
||||
// NOTE: list must be guaranteed to end in 0
|
||||
unsigned int count_positive8(unsigned char *list)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
|
9
utils.h
9
utils.h
@ -16,8 +16,8 @@ typedef struct insn_map {
|
||||
unsigned short id;
|
||||
unsigned short mapid;
|
||||
#ifndef CAPSTONE_DIET
|
||||
unsigned char regs_use[12]; // list of implicit registers used by this instruction
|
||||
unsigned char regs_mod[20]; // list of implicit registers modified by this instruction
|
||||
uint16_t regs_use[12]; // list of implicit registers used by this instruction
|
||||
uint16_t regs_mod[20]; // list of implicit registers modified by this instruction
|
||||
unsigned char groups[8]; // list of group this instruction belong to
|
||||
bool branch; // branch instruction?
|
||||
bool indirect_branch; // indirect branch instruction?
|
||||
@ -40,7 +40,8 @@ int name2id(name_map* map, int max, const char *name);
|
||||
|
||||
// count number of positive members in a list.
|
||||
// NOTE: list must be guaranteed to end in 0
|
||||
unsigned int count_positive(unsigned char *list);
|
||||
unsigned int count_positive(uint16_t *list);
|
||||
unsigned int count_positive8(unsigned char *list);
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
@ -51,5 +52,7 @@ char *cs_strdup(const char *str);
|
||||
// we need this since Windows doesnt have snprintf()
|
||||
int cs_snprintf(char *buffer, size_t size, const char *fmt, ...);
|
||||
|
||||
#define CS_AC_IGNORE (1 << 7)
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user