docs: def checksec_app(_parser, _, args):  # pragma: no cover
      """
      Check security features of an ELF file.
      """
  
      import sys
      import argparse
      import csv
      import os.path
  
      def checksec(elf, path, fortifiable_funcs):
          relro = 0
          nx = False
          pie = 0
          rpath = False
          runpath = False
  
          for header in elf.program_headers:
              if header.type == ELF.ProgramHeader.Type.gnu_relro:
                  relro = 1
              elif header.type == ELF.ProgramHeader.Type.gnu_stack:
                  if not header.flags & ELF.ProgramHeader.Flags.x:
                      nx = True
  
          if elf.type == ELF.Type.shared:
              pie = 1
  
          for entry in elf.dynamic_section_entries:
              if entry.type == ELF.DynamicSectionEntry.Type.bind_now and relro == 1:
                  relro = 2
              elif entry.type == ELF.DynamicSectionEntry.Type.flags and \
                      entry.value & ELF.DynamicSectionEntry.Flags.bind_now:
                  relro = 2
              elif entry.type == ELF.DynamicSectionEntry.Type.flags_1 and \
                      entry.value & ELF.DynamicSectionEntry.Flags_1.now:
                  relro = 2
              elif entry.type == ELF.DynamicSectionEntry.Type.debug and pie == 1:
                  pie = 2
              elif entry.type == ELF.DynamicSectionEntry.Type.rpath:
                  rpath = True
              elif entry.type == ELF.DynamicSectionEntry.Type.runpath:
                  runpath = True
  
          rtl_symbol_names = set(
              symbol.name
              for symbol in elf.symbols
              if symbol.name and symbol.shndx == ELF.Symbol.SpecialSection.undef
          )
  
          fortified = fortifiable_funcs & rtl_symbol_names
          unfortified = fortifiable_funcs & set('__%s_chk' % symbol_name for symbol_name in rtl_symbol_names)
  
          canary = '__stack_chk_fail' in rtl_symbol_names
  
          return {
              'path': path,
              'relro': relro,
              'nx': nx,
              'pie': pie,
              'rpath': rpath,
              'runpath': runpath,
              'canary': canary,
              'fortified': len(fortified),
              'unfortified': len(unfortified),
              'fortifiable': len(fortified | unfortified),
          }
  
      def check_paths(paths, fortifiable_funcs):
          for path in paths:
              if os.path.isdir(path):
                  for data in check_paths(
                          (os.path.join(path, fn) for fn in os.listdir(path) if fn not in ('.', '..')),
                          fortifiable_funcs,
                  ):
                      yield data
              else:
                  try:
                      elf = ELF(path)
                  except:
                      continue
  
                  yield checksec(elf, path, fortifiable_funcs)
  
      parser = argparse.ArgumentParser(
          prog=_parser.prog,
          description=_parser.description,
      )
      parser.add_argument('path', nargs='+', help='ELF file to check security features of')
      parser.add_argument(
          '-f', '--format',
          dest='format',
          choices=['text', 'csv'],
          default='text',
          help='set output format'
      )
      parser.add_argument(
          '-l', '--libc',
          dest='libc',
          help='path to the applicable libc.so'
      )
      args = parser.parse_args(args)
  
      if args.libc:
          libc = ELF(args.libc)
          fortifiable_funcs = set([
              symbol.name
              for symbol in libc.symbols
              if symbol.name.startswith('__') and symbol.name.endswith('_chk')
          ])
      else:
          fortifiable_funcs = set('''__wctomb_chk __wcsncat_chk __mbstowcs_chk __strncpy_chk __syslog_chk __mempcpy_chk
                                     __fprintf_chk __recvfrom_chk __readlinkat_chk __wcsncpy_chk __fread_chk
                                     __getlogin_r_chk __vfwprintf_chk __recv_chk __strncat_chk __printf_chk __confstr_chk
                                     __pread_chk __ppoll_chk __ptsname_r_chk __wcscat_chk __snprintf_chk __vwprintf_chk
                                     __memset_chk __memmove_chk __gets_chk __fgetws_unlocked_chk __asprintf_chk __poll_chk
                                     __fdelt_chk __fgets_unlocked_chk __strcat_chk __vsyslog_chk __stpcpy_chk
                                     __vdprintf_chk __strcpy_chk __obstack_printf_chk __getwd_chk __pread64_chk
                                     __wcpcpy_chk __fread_unlocked_chk __dprintf_chk __fgets_chk __wcpncpy_chk
                                     __obstack_vprintf_chk __wprintf_chk __getgroups_chk __wcscpy_chk __vfprintf_chk
                                     __fgetws_chk __vswprintf_chk __ttyname_r_chk __mbsrtowcs_chk
                                     __wmempcpy_chk __wcsrtombs_chk __fwprintf_chk __read_chk __getcwd_chk __vsnprintf_chk
                                     __memcpy_chk __wmemmove_chk __vasprintf_chk __sprintf_chk __vprintf_chk
                                     __mbsnrtowcs_chk __wcrtomb_chk __realpath_chk __vsprintf_chk __wcsnrtombs_chk
                                     __gethostname_chk __swprintf_chk __readlink_chk __wmemset_chk __getdomainname_chk
                                     __wmemcpy_chk __longjmp_chk __stpncpy_chk __wcstombs_chk'''.split())
  
      if args.format == 'text':
          print('RELRO    CANARY  NX   PIE  RPATH  RUNPATH  FORTIFIED  PATH')
          for data in check_paths(args.path, fortifiable_funcs):
              print('{:7}  {:6}  {:3}  {:3}  {:5}  {:7}  {:>9}  {}'.format(
                  ('No', 'Partial', 'Full')[data['relro']],
                  'Yes' if data['canary'] else 'No',
                  'Yes' if data['nx'] else 'No',
                  ('No', 'DSO', 'Yes')[data['pie']],
                  'Yes' if data['rpath'] else 'No',
                  'Yes' if data['runpath'] else 'No',
                  '{}/{}/{}'.format(data['fortified'], data['unfortified'], data['fortifiable']),
                  data['path']
              ))
      else:
          writer = csv.writer(sys.stdout)
          writer.writerow(['path', 'relro', 'canary', 'nx', 'pie', 'rpath', 'runpath', 'fortified', 'unfortified',
                           'fortifiable'])
          for data in check_paths(args.path, fortifiable_funcs):
              writer.writerow([
                  data['path'],
                  ('no', 'partial', 'full')[data['relro']],
                  'yes' if data['canary'] else 'no',
                  'yes' if data['nx'] else 'no',
                  ('no', 'dso', 'yes')[data['pie']],
                  'yes' if data['rpath'] else 'no',
                  'yes' if data['runpath'] else 'no',
                  data['fortified'],
                  data['unfortified'],
                  data['fortifiable'],
              ])