Find ROP gadgets in an ELF binary.

def gadget_app(_parser, cmd, args):  # pragma: no cover
    """
    Find ROP gadgets in an ELF binary.
    """

    parser = argparse.ArgumentParser(
        prog=_parser.prog,
        description=_parser.description,
    )
    parser.add_argument('file', help='ELF file to find gadgets in')
    parser.add_argument('gadget', help='the assembler source or reghex expression')
    parser.add_argument(
        '--reghex', '-r',
        dest='mode',
        action='store_const',
        const='reghex',
        help='use reghex expression (hex bytes interspaced with ? for wildcard)',
    )
    parser.add_argument(
        '--asm', '-a',
        dest='mode',
        action='store_const',
        const='asm',
        help='use assembler expression (separate lines with semi-colon)',
    )
    parser.add_argument(
        '--all', '-l',
        dest='unique',
        action='store_const',
        const=False,
        default=True,
        help='also show non-unique gadgets',
    )
    args = parser.parse_args(args)

    if args.mode is None:
        try:
            pwnypack.util.reghex(args.gadget)
            args.mode = 'reghex'
        except SyntaxError:
            args.mode = 'asm'

    elf = pwnypack.elf.ELF(args.file)

    if args.mode == 'reghex':
        try:
            gadget = pwnypack.util.reghex(args.gadget)
        except SyntaxError:
            print('Invalid reghex pattern.')
            sys.exit(1)
    else:
        try:
            gadget = pwnypack.util.reghex('*'.join([
                pwnypack.codec.enhex(pwnypack.asm.asm(piece.replace(';', '\n'), target=elf))
                for piece in ';'.join([line.strip() for line in args.gadget.split(';')]).split('*')
            ]))
        except SyntaxError as e:
            print('Could not assemble:', e.msg)
            sys.exit(1)

    matches = find_gadget(
        elf,
        gadget,
        unique=args.unique
    )

    if not matches:
        print('No gadgets found.', file=sys.stdout)
        return

    longest_gadget = max(len(m['gadget']) for m in matches)
    fmt = '  0x%%0%dx: [ %%-%ds ] %%s' % (elf.bits / 4, longest_gadget * 3 - 1)

    current_section = None

    for match in matches:
        if match['section'].name != current_section:
            if current_section is not None:
                print()
            print('Section: %s' % match['section'].name)
            current_section = match['section'].name

        hex_gadget = pwnypack.codec.enhex(match['gadget'])
        print(fmt % (
            match['addr'],
            ' '.join(
                hex_gadget[i:i+2]
                for i in range(0, len(hex_gadget), 2)
            ),
            ' ; '.join(match['asm'])
        ))

    print()