import capstone as cs
import logging
from archinfo.arch_arm import is_arm_arch
from ..misc.ux import once
l = logging.getLogger(name=__name__)
INS_GROUP_INFO = {
"X86": {
cs.x86.X86_GRP_CALL: "call",
cs.x86.X86_GRP_JUMP: "branch",
cs.x86.X86_GRP_RET: "return",
},
"AMD64": {
cs.x86.X86_GRP_CALL: "call",
cs.x86.X86_GRP_JUMP: "branch",
cs.x86.X86_GRP_RET: "return",
},
"ARM": {
cs.arm.ARM_GRP_CALL: "call",
cs.arm.ARM_GRP_BRANCH_RELATIVE: "branch",
cs.arm.ARM_GRP_JUMP: "branch",
},
}
INS_GROUP_INFO["ARMEL"] = INS_GROUP_INFO["ARM"]
INS_GROUP_INFO["ARMHF"] = INS_GROUP_INFO["ARM"]
INS_GROUP_INFO["ARMCortexM"] = INS_GROUP_INFO["ARM"]
try:
INS_GROUP_INFO["MIPS32"] = {
cs.mips.MIPS_GRP_CALL: "call",
cs.mips.MIPS_GRP_JUMP: "branch",
cs.mips.MIPS_GRP_RET: "return",
}
except AttributeError:
# The installed capstone is too old - it does not support cs.mips.MIPS_GRP_*
pass
INS_INFO = {
"MIPS32": {
cs.mips.MIPS_INS_JAL: "call",
cs.mips.MIPS_INS_BAL: "branch",
}
}
[docs]def decode_instruction(arch, instr):
# this is clearly architecture specific
arch_name = arch.name
if arch_name == "MIPS32" and once("mips-instruction-groups"):
l.warning("Your version of capstone does not support MIPS instruction groups.")
insn_info = None
info = INS_GROUP_INFO.get(arch_name, None)
if info is not None:
for group in instr.insn.insn.groups:
insn_info = info.get(group, None)
if insn_info is not None:
break
if insn_info is None:
info = INS_INFO.get(arch_name, None)
if info is not None:
insn_info = info.get(instr.insn.insn.id, None)
if insn_info is None:
return
instr.type = insn_info
if instr.type in ("call", "branch"):
# determine if this is a direct or indirect call/branch
if arch_name in ("X86", "AMD64"):
last_operand = instr.insn.operands[-1]
if last_operand.type == cs.x86.X86_OP_IMM:
instr.branch_type = "direct"
else:
instr.branch_type = "indirect"
instr.branch_target_operand = len(instr.insn.operands) - 1
elif is_arm_arch(arch):
last_operand = instr.insn.operands[-1]
if last_operand.type == cs.arm.ARM_OP_IMM:
instr.branch_type = "direct"
else:
instr.branch_type = "indirect"
instr.branch_target_operand = len(instr.insn.operands) - 1
elif arch_name == "MIPS32":
# check the last operand
last_operand = instr.insn.operands[-1]
if last_operand.type == cs.mips.MIPS_OP_REG:
instr.branch_type = "indirect"
else:
instr.branch_type = "direct"
instr.branch_target_operand = len(instr.insn.operands) - 1