'Helper to make finding ROP gadets easier.
Also provides a shorthand for ``.call()``:
``rop.function(args)`` is equivalent to ``rop.call(function, args)``
>>> elf=ELF(which(\'bash\'))
>>> rop=ROP([elf])
>>> rop.rdi     == rop.search(regs=[\'rdi\'], order = \'regs\')
True
>>> rop.r13_r14_r15_rbp == rop.search(regs=[\'r13\',\'r14\',\'r15\',\'rbp\'], order = \'regs\')
True
>>> rop.ret_8   == rop.search(move=8)
True
>>> rop.ret     != None
True'

def __getattr__(self, attr):

    gadget = collections.namedtuple('gadget', ['address', 'details'])
    bad_attrs = ['trait_names', 'download', 'upload']
    if ((attr in self.__dict__) or (attr in bad_attrs) or attr.startswith('_')):
        raise AttributeError(('ROP    instance    has    no    attribute    %r' % attr))
    if attr.startswith('ret'):
        count = context.bytes
        if ('_' in attr):
            count = int(attr.split('_')[1])
        return self.search(move=count)
    if (attr in ('int80', 'syscall', 'sysenter')):
        mapping = {'int80': 'int    0x80', 'syscall': 'syscall', 'sysenter': 'sysenter'}
        for each in self.gadgets:
            if (self.gadgets[each]['insns'] == [mapping[attr]]):
                return gadget(each, self.gadgets[each])
        return None
    x86_suffixes = ['ax', 'bx', 'cx', 'dx', 'bp', 'sp', 'di', 'si', 'r8', 'r9', '10', '11', '12', '13', '14', '15']
    if all(map((lambda x: (x[(-2):] in x86_suffixes)), attr.split('_'))):
        return self.search(regs=attr.split('_'), order='regs')
    def call(*args):
        return self.call(attr, args)
    return call
