idautils.py: added procregs to identify registers and modified DecodeInstruction().

It is now possible to identify the registers of a decoded instruction with:

cmd = DecodeInstruction(here())
if cmd[0].is_reg(proc_regs.eax): print "EAX is used"

or something like:

if cmd[1].is_reg(proc_regs.al): print "al is used"
This commit is contained in:
elias.bachaalany 2009-10-19 07:17:22 +00:00
parent c21a932cec
commit 99c60a82de

View File

@ -266,7 +266,7 @@ def FuncItems(start):
def DecodeInstruction(ea): def DecodeInstruction(ea):
""" """
Decodes an instruction and returns a insn_t like class Decodes an instruction and returns an insn_t like class
@param ea: address to decode @param ea: address to decode
@ -278,19 +278,30 @@ def DecodeInstruction(ea):
insn = idaapi.get_current_instruction() insn = idaapi.get_current_instruction()
if not insn: if not insn:
return None return None
class dup(object):
class _insn(object):
def __getitem__(self, index):
if index > len(self.Operands):
raise StopIteration
return self.Operands[index]
class _op(_reg_dtyp_t):
def __init__(self, op): def __init__(self, op):
for x in dir(op): _copy_obj(op, self)
if x.startswith("__") and x.endswith("__"): _reg_dtyp_t.__init__(self, op.reg, op.dtyp)
continue def is_reg(self, r):
setattr(self, x, getattr(op, x)) """Checks if the operand is the given processor register"""
r = dup(insn) return self.type == idaapi.o_reg and self == r
r.Operands = [] def has_reg(self, r):
"""Checks if the operand accesses the given processor register"""
return self.reg == r.reg
r = _copy_obj(insn, _insn())
r.Operands = [] # to hold the operands
for n in xrange(0, idaapi.UA_MAXOP): for n in xrange(0, idaapi.UA_MAXOP):
t = idaapi.get_instruction_operand(insn, n) t = idaapi.get_instruction_operand(insn, n)
if t.type == idaapi.o_void: if t.type == idaapi.o_void:
break break
r.Operands.append(dup(t)) r.Operands.append(_op(t))
return r return r
@ -469,6 +480,50 @@ def Assemble(ea, line):
idc.Batch(old_batch) idc.Batch(old_batch)
return ret return ret
def _copy_obj(src, dest):
"""
Copy non private/non callable attributes from a class instance to another
@param src: Source class to copy from
@param dest: If it is a string then it designates the new class type that will be created and copied to.
Otherwise dest should be an instance of another class
@return: A new instance or "dest"
"""
if type(dest) == types.StringType:
dest = new.classobj(dest, (), {})
for x in dir(src):
if x.startswith("__") and x.endswith("__"):
continue
t = getattr(src, x)
if callable(t):
continue
setattr(dest, x, t)
return dest
class _reg_dtyp_t(object):
"""
INTERNAL
This class describes a register's number and dtyp.
The equal operator is overloaded so that two instances can be tested for equality
"""
def __init__(self, reg, dtyp):
self.reg = reg
self.dtyp = dtyp
def __eq__(self, other):
return (self.reg == other.reg) and (self.dtyp == other.dtyp)
class _procregs(object):
"""Utility class allowing the users to identify registers in a decoded instruction"""
def __getattr__(self, attr):
ri = idaapi.reg_info_t()
if not idaapi.parse_reg_name(attr, ri):
raise AttributeError()
r = _reg_dtyp_t(ri.reg, ord(idaapi.get_dtyp_by_size(ri.size)))
self.__dict__[attr] = r
return r
def __setattr__(self, attr, value):
raise AttributeError(attr)
class _cpu(object): class _cpu(object):
"Simple wrapper around GetRegValue/SetRegValue" "Simple wrapper around GetRegValue/SetRegValue"
@ -481,3 +536,4 @@ class _cpu(object):
return idc.SetRegValue(value, name) return idc.SetRegValue(value, name)
cpu = _cpu() cpu = _cpu()
procregs = _procregs()