LCOV - code coverage report
Current view: top level - src - elfclassify.c (source / functions) Hit Total Coverage
Test: elfutils-0.184 Lines: 224 412 54.4 %
Date: 2021-05-22 20:18:50 Functions: 17 22 77.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 162 319 50.8 %

           Branch data     Line data    Source code
       1                 :            : /* Classification of ELF files.
       2                 :            :    Copyright (C) 2019 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of the GNU General Public License as published by
       7                 :            :    the Free Software Foundation; either version 3 of the License, or
       8                 :            :    (at your option) any later version.
       9                 :            : 
      10                 :            :    elfutils is distributed in the hope that it will be useful, but
      11                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13                 :            :    GNU General Public License for more details.
      14                 :            : 
      15                 :            :    You should have received a copy of the GNU General Public License
      16                 :            :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      17                 :            : 
      18                 :            : #include <config.h>
      19                 :            : 
      20                 :            : #include <argp.h>
      21                 :            : #include <error.h>
      22                 :            : #include <fcntl.h>
      23                 :            : #include <gelf.h>
      24                 :            : #include <stdbool.h>
      25                 :            : #include <stddef.h>
      26                 :            : #include <stdio.h>
      27                 :            : #include <stdlib.h>
      28                 :            : #include <string.h>
      29                 :            : #include <sys/stat.h>
      30                 :            : #include <unistd.h>
      31                 :            : 
      32                 :            : #include ELFUTILS_HEADER(elf)
      33                 :            : #include ELFUTILS_HEADER(dwelf)
      34                 :            : #include "printversion.h"
      35                 :            : 
      36                 :            : /* Name and version of program.  */
      37                 :            : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      38                 :            : 
      39                 :            : /* Bug report address.  */
      40                 :            : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      41                 :            : 
      42                 :            : /* Set by parse_opt.  */
      43                 :            : static int verbose;
      44                 :            : 
      45                 :            : /* Set by the main function.  */
      46                 :            : static const char *current_path;
      47                 :            : 
      48                 :            : /* Set by open_file.  */
      49                 :            : static int file_fd = -1;
      50                 :            : 
      51                 :            : /* Set by issue or elf_issue.  */
      52                 :            : static bool issue_found;
      53                 :            : 
      54                 :            : /* Non-fatal issue occurred while processing the current_path.  */
      55                 :            : static void
      56                 :          0 : issue (int e, const char *msg)
      57                 :            : {
      58         [ #  # ]:          0 :   if (verbose >= 0)
      59                 :            :     {
      60         [ #  # ]:          0 :       if (current_path == NULL)
      61                 :          0 :         error (0, e, "%s", msg);
      62                 :            :       else
      63                 :          0 :         error (0, e, "%s '%s'", msg, current_path);
      64                 :            :     }
      65                 :          0 :   issue_found = true;
      66                 :          0 : }
      67                 :            : 
      68                 :            : /* Non-fatal issue occurred while processing the current ELF.  */
      69                 :            : static void
      70                 :          0 : elf_issue (const char *msg)
      71                 :            : {
      72         [ #  # ]:          0 :   if (verbose >= 0)
      73                 :          0 :     error (0, 0, "%s: %s: '%s'", msg, elf_errmsg (-1), current_path);
      74                 :          0 :   issue_found = true;
      75                 :          0 : }
      76                 :            : 
      77                 :            : /* Set by parse_opt.  */
      78                 :            : static bool flag_only_regular_files;
      79                 :            : 
      80                 :            : static bool
      81                 :        600 : open_file (void)
      82                 :            : {
      83         [ -  + ]:        600 :   if (verbose > 1)
      84                 :          0 :     fprintf (stderr, "debug: processing file: %s\n", current_path);
      85                 :            : 
      86                 :       1200 :   file_fd = open (current_path, O_RDONLY | (flag_only_regular_files
      87         [ +  - ]:        600 :                                             ? O_NOFOLLOW : 0));
      88         [ -  + ]:        600 :   if (file_fd < 0)
      89                 :            :     {
      90   [ #  #  #  # ]:          0 :       if (!flag_only_regular_files || errno != ELOOP)
      91                 :          0 :         issue (errno, N_("opening"));
      92                 :          0 :       return false;
      93                 :            :     }
      94                 :            : 
      95                 :        600 :   struct stat st;
      96         [ -  + ]:        600 :   if (fstat (file_fd, &st) != 0)
      97                 :            :     {
      98                 :          0 :       issue (errno, N_("reading"));
      99                 :          0 :       return false;
     100                 :            :     }
     101                 :            : 
     102                 :            :   /* Don't even bother with directories.  */
     103         [ +  - ]:        600 :   if (S_ISDIR (st.st_mode)
     104   [ -  +  -  - ]:        600 :       || (flag_only_regular_files && !S_ISREG (st.st_mode)))
     105                 :          0 :     return false;
     106                 :            : 
     107                 :            :   return true;
     108                 :            : }
     109                 :            : 
     110                 :            : static void
     111                 :        600 : close_file (void)
     112                 :            : {
     113         [ +  - ]:        600 :   if (file_fd >= 0)
     114                 :            :     {
     115                 :        600 :       close (file_fd);
     116                 :        600 :       file_fd = -1;
     117                 :            :     }
     118                 :        600 : }
     119                 :            : 
     120                 :            : /* Set by open_elf.  */
     121                 :            : static Elf *elf;
     122                 :            : 
     123                 :            : /* Set by parse_opt.  */
     124                 :            : static bool flag_compressed;
     125                 :            : 
     126                 :            : static bool
     127                 :        600 : open_elf (void)
     128                 :            : {
     129         [ -  + ]:        600 :   if (!open_file ())
     130                 :            :     {
     131                 :            :       /* Make sure the file descriptor is gone.  */
     132                 :          0 :       close_file ();
     133                 :          0 :       return false;
     134                 :            :     }
     135                 :            : 
     136         [ -  + ]:        600 :   if (flag_compressed)
     137                 :          0 :     elf = dwelf_elf_begin (file_fd);
     138                 :            :   else
     139                 :        600 :     elf = elf_begin (file_fd, ELF_C_READ, NULL);
     140                 :            : 
     141         [ -  + ]:        600 :   if (elf == NULL)
     142                 :            :     {
     143                 :          0 :       elf_issue ("opening ELF file");
     144                 :          0 :       close_file ();
     145                 :          0 :       return false;
     146                 :            :     }
     147                 :            : 
     148                 :            :   return true;
     149                 :            : }
     150                 :            : 
     151                 :            : static void
     152                 :        600 : close_elf (void)
     153                 :            : {
     154         [ +  - ]:        600 :   if (elf != NULL)
     155                 :            :     {
     156                 :        600 :       elf_end (elf);
     157                 :        600 :       elf = NULL;
     158                 :            :     }
     159                 :            : 
     160                 :        600 :   close_file ();
     161                 :        600 : }
     162                 :            : 
     163                 :            : static const char *
     164                 :          0 : elf_kind_string (int kind)
     165                 :            : {
     166   [ #  #  #  #  :          0 :   switch (kind)
                      # ]
     167                 :            :     {
     168                 :            :     case ELF_K_NONE:
     169                 :            :       return "ELF_K_NONE";
     170                 :          0 :     case ELF_K_AR:
     171                 :          0 :       return "ELF_K_AR";
     172                 :          0 :     case ELF_K_COFF:
     173                 :          0 :       return "ELF_K_COFF"; /* libelf doesn't really support this.  */
     174                 :          0 :     case ELF_K_ELF:
     175                 :          0 :       return "ELF_K_ELF";
     176                 :          0 :     default:
     177                 :          0 :       return "<unknown>";
     178                 :            :     }
     179                 :            : }
     180                 :            : 
     181                 :            : static const char *
     182                 :          0 : elf_type_string (int type)
     183                 :            : {
     184   [ #  #  #  #  :          0 :   switch (type)
                   #  # ]
     185                 :            :     {
     186                 :            :     case ET_NONE:
     187                 :            :       return "ET_NONE";
     188                 :          0 :     case ET_REL:
     189                 :          0 :       return "ET_REL";
     190                 :          0 :     case ET_EXEC:
     191                 :          0 :       return "ET_EXEC";
     192                 :          0 :     case ET_DYN:
     193                 :          0 :       return "ET_DYN";
     194                 :          0 :     case ET_CORE:
     195                 :          0 :       return "ET_CORE";
     196                 :          0 :     default:
     197                 :          0 :       return "<unknown>";
     198                 :            :     }
     199                 :            : }
     200                 :            : 
     201                 :            : static int elf_type;
     202                 :            : static bool has_program_load;
     203                 :            : static bool has_sections;
     204                 :            : static bool has_bits_alloc;
     205                 :            : static bool has_program_interpreter;
     206                 :            : static bool has_dynamic;
     207                 :            : static bool has_soname;
     208                 :            : static bool has_pie_flag;
     209                 :            : static bool has_dt_debug;
     210                 :            : static bool has_symtab;
     211                 :            : static bool has_debug_sections;
     212                 :            : static bool has_modinfo;
     213                 :            : static bool has_gnu_linkonce_this_module;
     214                 :            : 
     215                 :            : static bool
     216                 :        600 : run_classify (void)
     217                 :            : {
     218                 :            :   /* Reset to unanalyzed default.  */
     219                 :        600 :   elf_type = 0;
     220                 :        600 :   has_program_load = false;
     221                 :        600 :   has_sections = false;
     222                 :        600 :   has_bits_alloc = false;
     223                 :        600 :   has_program_interpreter = false;
     224                 :        600 :   has_dynamic = false;
     225                 :        600 :   has_soname = false;
     226                 :        600 :   has_pie_flag = false;
     227                 :        600 :   has_dt_debug = false;
     228                 :        600 :   has_symtab = false;
     229                 :        600 :   has_debug_sections = false;
     230                 :        600 :   has_modinfo = false;
     231                 :        600 :   has_gnu_linkonce_this_module = false;
     232                 :            : 
     233                 :        600 :   int kind = elf_kind (elf);
     234         [ -  + ]:        600 :   if (verbose > 0)
     235                 :          0 :     fprintf (stderr, "info: %s: ELF kind: %s (0x%x)\n", current_path,
     236                 :            :              elf_kind_string (kind), kind);
     237         [ +  + ]:        600 :   if (kind != ELF_K_ELF)
     238                 :            :     return true;
     239                 :            : 
     240                 :        590 :   GElf_Ehdr ehdr_storage;
     241                 :        590 :   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_storage);
     242         [ -  + ]:        590 :   if (ehdr == NULL)
     243                 :            :     {
     244                 :          0 :       elf_issue (N_("ELF header"));
     245                 :          0 :       return false;
     246                 :            :     }
     247                 :        590 :   elf_type = ehdr->e_type;
     248                 :            : 
     249                 :            :   /* Examine program headers.  */
     250                 :        590 :   GElf_Phdr dyn_seg = { .p_type = 0 };
     251                 :            :   {
     252                 :        590 :     size_t nphdrs;
     253         [ -  + ]:        590 :     if (elf_getphdrnum (elf, &nphdrs) != 0)
     254                 :            :       {
     255                 :          0 :         elf_issue (N_("program headers"));
     256                 :          0 :         return false;
     257                 :            :       }
     258         [ +  + ]:       4178 :     for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
     259                 :            :       {
     260                 :       3588 :         GElf_Phdr phdr_storage;
     261                 :       3588 :         GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
     262         [ -  + ]:       3588 :         if (phdr == NULL)
     263                 :            :           {
     264                 :          0 :             elf_issue (N_("program header"));
     265                 :          0 :             return false;
     266                 :            :           }
     267         [ +  + ]:       3588 :         if (phdr->p_type == PT_DYNAMIC)
     268                 :            :           {
     269                 :        252 :             dyn_seg = *phdr;
     270                 :        252 :             has_dynamic = true;
     271                 :            :           }
     272         [ +  + ]:       3588 :         if (phdr->p_type == PT_INTERP)
     273                 :        132 :           has_program_interpreter = true;
     274         [ +  + ]:       3588 :         if (phdr->p_type == PT_LOAD)
     275                 :       2002 :           has_program_load = true;
     276                 :            :       }
     277                 :            :   }
     278                 :            : 
     279                 :            :   /* Do we have sections?  */
     280                 :            :   {
     281                 :        590 :     size_t nshdrs;
     282         [ -  + ]:        590 :     if (elf_getshdrnum (elf, &nshdrs) != 0)
     283                 :            :       {
     284                 :          0 :         elf_issue (N_("section headers"));
     285                 :          0 :         return false;
     286                 :            :       }
     287         [ +  + ]:        590 :     if (nshdrs > 0)
     288                 :        470 :       has_sections = true;
     289                 :            :   }
     290                 :            : 
     291                 :            :   {
     292                 :        590 :     size_t shstrndx;
     293         [ -  + ]:        590 :     if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
     294                 :            :       {
     295                 :          0 :         elf_issue (N_("section header string table index"));
     296                 :          0 :         return false;
     297                 :            :       }
     298                 :            : 
     299                 :            :     Elf_Scn *scn = NULL;
     300                 :      26822 :     while (true)
     301                 :      13116 :       {
     302                 :      13706 :         scn = elf_nextscn (elf, scn);
     303         [ +  + ]:      13706 :         if (scn == NULL)
     304                 :            :           break;
     305                 :      13116 :         GElf_Shdr shdr_storage;
     306                 :      13116 :         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
     307         [ -  + ]:      13116 :         if (shdr == NULL)
     308                 :            :           {
     309                 :          0 :             elf_issue (N_("could not obtain section header"));
     310                 :          0 :             return false;
     311                 :            :           }
     312                 :      13116 :         const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
     313         [ -  + ]:      13116 :         if (section_name == NULL)
     314                 :            :           {
     315                 :          0 :             elf_issue(N_("could not obtain section name"));
     316                 :          0 :             return false;
     317                 :            :           }
     318         [ -  + ]:      13116 :         if (verbose > 2)
     319                 :          0 :           fprintf (stderr, "debug: section header %s (type %d) found\n",
     320                 :            :                    section_name, shdr->sh_type);
     321         [ +  + ]:      13116 :         if (shdr->sh_type == SHT_SYMTAB)
     322                 :            :           {
     323         [ -  + ]:        430 :             if (verbose > 1)
     324                 :          0 :               fputs ("debug: symtab section found\n", stderr);
     325                 :        430 :             has_symtab = true;
     326                 :            :           }
     327                 :            :         /* NOBITS and NOTE sections can be in any file.  We want to be
     328                 :            :            sure there is at least one other allocated section.  */
     329                 :      13116 :         if (shdr->sh_type != SHT_NOBITS
     330         [ +  + ]:      13116 :             && shdr->sh_type != SHT_NOTE
     331         [ +  + ]:      10040 :             && (shdr->sh_flags & SHF_ALLOC) != 0)
     332                 :            :           {
     333   [ -  +  -  - ]:       4706 :             if (verbose > 1 && !has_bits_alloc)
     334                 :          0 :               fputs ("debug: allocated (non-nobits/note) section found\n",
     335                 :            :                      stderr);
     336                 :       4706 :             has_bits_alloc = true;
     337                 :            :           }
     338                 :      13116 :         const char *debug_prefix = ".debug_";
     339                 :      13116 :         const char *zdebug_prefix = ".zdebug_";
     340         [ +  + ]:      13116 :         if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0
     341         [ +  + ]:      11248 :             || strncmp (section_name, zdebug_prefix,
     342                 :            :                         strlen (zdebug_prefix)) == 0)
     343                 :            :           {
     344   [ -  +  -  - ]:       2274 :             if (verbose > 1 && !has_debug_sections)
     345                 :          0 :               fputs ("debug: .debug_* section found\n", stderr);
     346                 :       2274 :             has_debug_sections = true;
     347                 :            :           }
     348         [ +  + ]:      13116 :         if (strcmp (section_name, ".modinfo") == 0)
     349                 :            :           {
     350         [ -  + ]:         80 :             if (verbose > 1)
     351                 :          0 :               fputs ("debug: .modinfo section found\n", stderr);
     352                 :         80 :             has_modinfo = true;
     353                 :            :           }
     354         [ +  + ]:      13116 :         if (strcmp (section_name, ".gnu.linkonce.this_module") == 0)
     355                 :            :           {
     356         [ -  + ]:         80 :             if (verbose > 1)
     357                 :          0 :               fputs ("debug: .gnu.linkonce.this_module section found\n",
     358                 :            :                      stderr);
     359                 :         80 :             has_gnu_linkonce_this_module = true;
     360                 :            :           }
     361                 :            :       }
     362                 :            :   }
     363                 :            : 
     364                 :            :   /* Examine the dynamic section.  */
     365         [ +  + ]:        590 :   if (has_dynamic)
     366                 :            :     {
     367                 :        252 :       Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset,
     368                 :            :                                              dyn_seg.p_filesz,
     369                 :            :                                              ELF_T_DYN);
     370         [ +  + ]:        252 :       if (data != NULL)
     371                 :       5270 :         for (int dyn_idx = 0; ; ++dyn_idx)
     372                 :       5270 :           {
     373                 :       5510 :             GElf_Dyn dyn_storage;
     374                 :       5510 :             GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
     375         [ +  + ]:       5510 :             if (dyn == NULL)
     376                 :            :               break;
     377         [ -  + ]:       5458 :             if (verbose > 2)
     378                 :       5458 :               fprintf (stderr, "debug: dynamic entry %d"
     379                 :            :                        " with tag %llu found\n",
     380                 :          0 :                        dyn_idx, (unsigned long long int) dyn->d_tag);
     381         [ +  + ]:       5458 :             if (dyn->d_tag == DT_SONAME)
     382                 :         16 :               has_soname = true;
     383   [ +  +  +  - ]:       5458 :             if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
     384                 :         32 :               has_pie_flag = true;
     385         [ +  + ]:       5458 :             if (dyn->d_tag == DT_DEBUG)
     386                 :         72 :               has_dt_debug = true;
     387         [ +  + ]:       5458 :             if (dyn->d_tag == DT_NULL)
     388                 :            :               break;
     389                 :            :           }
     390                 :            :     }
     391                 :            : 
     392         [ -  + ]:        590 :   if (verbose > 0)
     393                 :            :     {
     394                 :          0 :       fprintf (stderr, "info: %s: ELF type: %s (0x%x)\n", current_path,
     395                 :            :                elf_type_string (elf_type), elf_type);
     396         [ #  # ]:          0 :       if (has_program_load)
     397                 :          0 :         fprintf (stderr, "info: %s: PT_LOAD found\n", current_path);
     398         [ #  # ]:          0 :       if (has_sections)
     399                 :          0 :         fprintf (stderr, "info: %s: has sections\n", current_path);
     400         [ #  # ]:          0 :       if (has_bits_alloc)
     401                 :          0 :         fprintf (stderr, "info: %s: allocated (real) section found\n",
     402                 :            :                  current_path);
     403         [ #  # ]:          0 :       if (has_program_interpreter)
     404                 :          0 :         fprintf (stderr, "info: %s: program interpreter found\n",
     405                 :            :                  current_path);
     406         [ #  # ]:          0 :       if (has_dynamic)
     407                 :          0 :         fprintf (stderr, "info: %s: dynamic segment found\n", current_path);
     408         [ #  # ]:          0 :       if (has_soname)
     409                 :          0 :         fprintf (stderr, "info: %s: soname found\n", current_path);
     410         [ #  # ]:          0 :       if (has_pie_flag)
     411                 :          0 :         fprintf (stderr, "info: %s: DF_1_PIE flag found\n", current_path);
     412         [ #  # ]:          0 :       if (has_dt_debug)
     413                 :          0 :         fprintf (stderr, "info: %s: DT_DEBUG found\n", current_path);
     414         [ #  # ]:          0 :       if (has_symtab)
     415                 :          0 :         fprintf (stderr, "info: %s: symbol table found\n", current_path);
     416         [ #  # ]:          0 :       if (has_debug_sections)
     417                 :          0 :         fprintf (stderr, "info: %s: .debug_* section found\n", current_path);
     418         [ #  # ]:          0 :       if (has_modinfo)
     419                 :          0 :         fprintf (stderr, "info: %s: .modinfo section found\n", current_path);
     420         [ #  # ]:          0 :       if (has_gnu_linkonce_this_module)
     421                 :          0 :         fprintf (stderr,
     422                 :            :                  "info: %s: .gnu.linkonce.this_module section found\n",
     423                 :            :                  current_path);
     424                 :            :     }
     425                 :            : 
     426                 :            :   return true;
     427                 :            : }
     428                 :            : 
     429                 :            : static bool
     430                 :        600 : is_elf (void)
     431                 :            : {
     432                 :        600 :   return elf_kind (elf) != ELF_K_NONE;
     433                 :            : }
     434                 :            : 
     435                 :            : static bool
     436                 :        600 : is_elf_file (void)
     437                 :            : {
     438                 :        600 :   return elf_kind (elf) == ELF_K_ELF;
     439                 :            : }
     440                 :            : 
     441                 :            : static bool
     442                 :        600 : is_elf_archive (void)
     443                 :            : {
     444                 :        600 :   return elf_kind (elf) == ELF_K_AR;
     445                 :            : }
     446                 :            : 
     447                 :            : static bool
     448                 :        600 : is_core (void)
     449                 :            : {
     450   [ +  +  +  + ]:        600 :   return elf_kind (elf) == ELF_K_ELF && elf_type == ET_CORE;
     451                 :            : }
     452                 :            : 
     453                 :            : /* Return true if the file is a loadable object, which basically means
     454                 :            :    it is an ELF file, but not a relocatable object or a core dump
     455                 :            :    file.  (The kernel and various userspace components can load ET_REL
     456                 :            :    files, but we disregard that for our classification purposes.)  */
     457                 :            : static bool
     458                 :       2814 : is_loadable (void)
     459                 :            : {
     460                 :       2814 :   return elf_kind (elf) == ELF_K_ELF
     461         [ +  + ]:       2774 :     && (elf_type == ET_EXEC || elf_type == ET_DYN)
     462         [ +  - ]:       1582 :     && has_program_load
     463   [ +  +  +  +  :       4396 :     && (!has_sections || has_bits_alloc); /* It isn't debug-only.  */
                   +  + ]
     464                 :            : }
     465                 :            : 
     466                 :            : /* Return true if the file is an ELF file which has a symbol table or
     467                 :            :    .debug_* sections (and thus can be stripped further).  */
     468                 :            : static bool
     469                 :        600 : is_unstripped (void)
     470                 :            : {
     471                 :        600 :   return elf_kind (elf) != ELF_K_NONE
     472         [ +  + ]:        600 :     && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
     473   [ +  -  +  +  :       1090 :     && (has_symtab || has_debug_sections);
                   +  - ]
     474                 :            : }
     475                 :            : 
     476                 :            : /* Return true if the file contains only debuginfo, but no loadable
     477                 :            :    program bits.  Then it is most likely a separate .debug file, a dwz
     478                 :            :    multi-file or a .dwo file.  Note that it can still be loadable,
     479                 :            :    but in that case the phdrs shouldn't be trusted.  */
     480                 :            : static bool
     481                 :        600 : is_debug_only (void)
     482                 :            : {
     483                 :        600 :   return elf_kind (elf) != ELF_K_NONE
     484         [ +  + ]:        600 :     && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
     485   [ +  +  +  + ]:        490 :     && (has_debug_sections || has_symtab)
     486   [ +  -  +  + ]:       1030 :     && !has_bits_alloc;
     487                 :            : }
     488                 :            : 
     489                 :            : static bool
     490                 :        808 : is_shared (void)
     491                 :            : {
     492         [ +  + ]:        808 :   if (!is_loadable ())
     493                 :            :     return false;
     494                 :            : 
     495                 :            :   /* The ELF type is very clear: this is an executable.  */
     496         [ +  + ]:        416 :   if (elf_type == ET_EXEC)
     497                 :            :     return false;
     498                 :            : 
     499                 :            :   /* If there is no dynamic section, the file cannot be loaded as a
     500                 :            :      shared object.  */
     501         [ +  - ]:        316 :   if (!has_dynamic)
     502                 :            :     return false;
     503                 :            : 
     504                 :            :   /* If the object is marked as PIE, it is definitely an executable,
     505                 :            :      and not a loadlable shared object.  */
     506         [ +  + ]:        316 :   if (has_pie_flag)
     507                 :            :     return false;
     508                 :            : 
     509                 :            :   /* Treat a DT_SONAME tag as a strong indicator that this is a shared
     510                 :            :      object.  */
     511         [ +  + ]:        252 :   if (has_soname)
     512                 :            :     return true;
     513                 :            : 
     514                 :            :   /* This is probably a PIE program: there is no soname, but a program
     515                 :            :      interpreter.  In theory, this file could be also a DSO with a
     516                 :            :      soname implied by its file name that can be run as a program.
     517                 :            :      This situation is impossible to resolve in the general case. */
     518         [ +  + ]:        220 :   if (has_program_interpreter)
     519                 :            :     return false;
     520                 :            : 
     521                 :            :   /* Roland McGrath mentions in
     522                 :            :      <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
     523                 :            :      that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
     524                 :            :      matches current binutils behavior (version 2.32).  DT_DEBUG is
     525                 :            :      added if bfd_link_executable returns true or if bfd_link_pic
     526                 :            :      returns false, depending on the architectures.  However, DT_DEBUG
     527                 :            :      is not documented as being specific to executables, therefore use
     528                 :            :      it only as a low-priority discriminator.  */
     529         [ -  + ]:        160 :   if (has_dt_debug)
     530                 :          0 :     return false;
     531                 :            : 
     532                 :            :   return true;
     533                 :            : }
     534                 :            : 
     535                 :            : static bool
     536                 :        600 : is_executable (void)
     537                 :            : {
     538         [ +  + ]:        600 :   if (!is_loadable ())
     539                 :            :     return false;
     540                 :            : 
     541                 :            :   /* A loadable object which is not a shared object is treated as an
     542                 :            :      executable.  */
     543                 :        208 :   return !is_shared ();
     544                 :            : }
     545                 :            : 
     546                 :            : /* Like is_executable, but the object can also be a shared library at
     547                 :            :    the same time.  */
     548                 :            : static bool
     549                 :        600 : is_program (void)
     550                 :            : {
     551         [ +  + ]:        600 :   if (!is_loadable ())
     552                 :            :     return false;
     553                 :            : 
     554                 :            :   /* The ELF type is very clear: this is an executable.  */
     555         [ +  + ]:        208 :   if (elf_type == ET_EXEC)
     556                 :            :     return true;
     557                 :            : 
     558                 :            :   /* If the object is marked as PIE, it is definitely an executable,
     559                 :            :      and not a loadlable shared object.  */
     560         [ +  + ]:        158 :   if (has_pie_flag)
     561                 :            :     return true;
     562                 :            : 
     563                 :            :   /* This is probably a PIE program. It isn't ET_EXEC, but has a
     564                 :            :      program interpreter. In theory, this file could be also a DSO
     565                 :            :      with a soname. This situation is impossible to resolve in the
     566                 :            :      general case. See is_shared. This is different from
     567                 :            :      is_executable.  */
     568         [ +  + ]:        126 :   if (has_program_interpreter)
     569                 :            :     return true;
     570                 :            : 
     571                 :            :   /* Roland McGrath mentions in
     572                 :            :      <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
     573                 :            :      that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
     574                 :            :      matches current binutils behavior (version 2.32).  DT_DEBUG is
     575                 :            :      added if bfd_link_executable returns true or if bfd_link_pic
     576                 :            :      returns false, depending on the architectures.  However, DT_DEBUG
     577                 :            :      is not documented as being specific to executables, therefore use
     578                 :            :      it only as a low-priority discriminator.  */
     579         [ -  + ]:         96 :   if (has_dt_debug)
     580                 :          0 :     return true;
     581                 :            : 
     582                 :            :   return false;
     583                 :            : }
     584                 :            : 
     585                 :            : /* Like is_shared but the library could also be an executable.  */
     586                 :            : static bool
     587                 :        600 : is_library  (void)
     588                 :            : {
     589                 :            :   /* Only ET_DYN can be shared libraries.  */
     590         [ +  + ]:        600 :   if (elf_type != ET_DYN)
     591                 :            :     return false;
     592                 :            : 
     593         [ +  + ]:        206 :   if (!is_loadable ())
     594                 :            :     return false;
     595                 :            : 
     596                 :            :   /* Without a PT_DYNAMIC segment the library cannot be loaded.  */
     597         [ +  - ]:        158 :   if (!has_dynamic)
     598                 :            :     return false;
     599                 :            : 
     600                 :            :   /* This really is a (PIE) executable.  See is_shared.  */
     601   [ +  +  +  + ]:        158 :   if (has_pie_flag || has_dt_debug)
     602                 :         62 :     return false;
     603                 :            : 
     604                 :            :   /* It could still (also) be a (PIE) executable, but most likely you
     605                 :            :      can dlopen it just fine.  */
     606                 :            :   return true;
     607                 :            : }
     608                 :            : 
     609                 :            : /* Returns true if the file is a linux kernel module (is ET_REL and
     610                 :            :    has the two magic sections .modinfo and .gnu.linkonce.this_module).  */
     611                 :            : static bool
     612                 :        600 : is_linux_kernel_module (void)
     613                 :            : {
     614                 :        600 :   return (elf_kind (elf) == ELF_K_ELF
     615         [ +  + ]:        590 :           && elf_type == ET_REL
     616         [ +  + ]:        198 :           && has_modinfo
     617   [ +  +  -  + ]:        680 :           && has_gnu_linkonce_this_module);
     618                 :            : }
     619                 :            : 
     620                 :            : enum classify_requirement { do_not_care, required, forbidden };
     621                 :            : 
     622                 :            : enum classify_check
     623                 :            : {
     624                 :            :   classify_elf,
     625                 :            :   classify_elf_file,
     626                 :            :   classify_elf_archive,
     627                 :            :   classify_core,
     628                 :            :   classify_unstripped,
     629                 :            :   classify_executable,
     630                 :            :   classify_program,
     631                 :            :   classify_shared,
     632                 :            :   classify_library,
     633                 :            :   classify_linux_kernel_module,
     634                 :            :   classify_debug_only,
     635                 :            :   classify_loadable,
     636                 :            : 
     637                 :            :   classify_check_last = classify_loadable
     638                 :            : };
     639                 :            : 
     640                 :            : enum
     641                 :            : {
     642                 :            :   classify_check_offset = 1000,
     643                 :            :   classify_check_not_offset = 2000,
     644                 :            : 
     645                 :            :   classify_flag_stdin = 3000,
     646                 :            :   classify_flag_stdin0,
     647                 :            :   classify_flag_no_stdin,
     648                 :            :   classify_flag_print,
     649                 :            :   classify_flag_print0,
     650                 :            :   classify_flag_no_print,
     651                 :            :   classify_flag_matching,
     652                 :            :   classify_flag_not_matching,
     653                 :            : };
     654                 :            : 
     655                 :            : static bool
     656                 :        842 : classify_check_positive (int key)
     657                 :            : {
     658                 :        842 :   return key >= classify_check_offset
     659                 :        842 :     && key <= classify_check_offset + classify_check_last;
     660                 :            : }
     661                 :            : 
     662                 :            : static bool
     663                 :        782 : classify_check_negative (int key)
     664                 :            : {
     665                 :        782 :   return key >= classify_check_not_offset
     666                 :        782 :     && key <= classify_check_not_offset + classify_check_last;
     667                 :            : }
     668                 :            : 
     669                 :            : /* Set by parse_opt.  */
     670                 :            : static enum classify_requirement requirements[classify_check_last + 1];
     671                 :            : static enum { no_stdin, do_stdin, do_stdin0 } flag_stdin;
     672                 :            : static enum { no_print, do_print, do_print0 } flag_print;
     673                 :            : static bool flag_print_matching = true;
     674                 :            : 
     675                 :            : static error_t
     676                 :        842 : parse_opt (int key, char *arg __attribute__ ((unused)),
     677                 :            :            struct argp_state *state __attribute__ ((unused)))
     678                 :            : {
     679         [ +  + ]:        842 :   if (classify_check_positive (key))
     680                 :         60 :     requirements[key - classify_check_offset] = required;
     681         [ +  + ]:        782 :   else if (classify_check_negative (key))
     682                 :         74 :     requirements[key - classify_check_not_offset] = forbidden;
     683                 :            :   else
     684   [ -  -  -  -  :        708 :     switch (key)
          -  -  -  +  -  
             -  -  -  + ]
     685                 :            :       {
     686                 :          0 :       case 'v':
     687                 :          0 :         ++verbose;
     688                 :          0 :         break;
     689                 :            : 
     690                 :          0 :       case 'q':
     691                 :          0 :         --verbose;
     692                 :          0 :         break;
     693                 :            : 
     694                 :          0 :       case 'z':
     695                 :          0 :         flag_compressed = true;
     696                 :          0 :         break;
     697                 :            : 
     698                 :          0 :       case 'f':
     699                 :          0 :         flag_only_regular_files = true;
     700                 :          0 :         break;
     701                 :            : 
     702                 :          0 :       case classify_flag_stdin:
     703                 :          0 :         flag_stdin = do_stdin;
     704                 :          0 :         break;
     705                 :            : 
     706                 :          0 :       case classify_flag_stdin0:
     707                 :          0 :         flag_stdin = do_stdin0;
     708                 :          0 :         break;
     709                 :            : 
     710                 :          0 :       case classify_flag_no_stdin:
     711                 :          0 :         flag_stdin = no_stdin;
     712                 :          0 :         break;
     713                 :            : 
     714                 :         38 :       case classify_flag_print:
     715                 :         38 :         flag_print = do_print;
     716                 :         38 :         break;
     717                 :            : 
     718                 :          0 :       case classify_flag_print0:
     719                 :          0 :         flag_print = do_print0;
     720                 :          0 :         break;
     721                 :            : 
     722                 :          0 :       case classify_flag_no_print:
     723                 :          0 :         flag_print = no_print;
     724                 :          0 :         break;
     725                 :            : 
     726                 :          0 :       case classify_flag_matching:
     727                 :          0 :         flag_print_matching = true;
     728                 :          0 :         break;
     729                 :            : 
     730                 :          0 :       case classify_flag_not_matching:
     731                 :          0 :         flag_print_matching = false;
     732                 :          0 :         break;
     733                 :            : 
     734                 :            :       default:
     735                 :            :         return ARGP_ERR_UNKNOWN;
     736                 :            :       }
     737                 :            : 
     738                 :            :   return 0;
     739                 :            : }
     740                 :            : 
     741                 :            : /* Perform requested checks against the file at current_path.  If
     742                 :            :    necessary, sets *STATUS to 1 if checks failed.  */
     743                 :            : static void
     744                 :        600 : process_current_path (int *status)
     745                 :            : {
     746                 :        600 :   bool checks_passed = true;
     747                 :            : 
     748   [ +  -  +  - ]:        600 :   if (open_elf () && run_classify ())
     749                 :        600 :     {
     750                 :        600 :       bool checks[] =
     751                 :            :         {
     752                 :            :          [classify_elf] = is_elf (),
     753                 :            :          [classify_elf_file] = is_elf_file (),
     754                 :            :          [classify_elf_archive] = is_elf_archive (),
     755                 :        600 :          [classify_core] = is_core (),
     756                 :        600 :          [classify_unstripped] = is_unstripped (),
     757                 :        600 :          [classify_executable] = is_executable (),
     758                 :        600 :          [classify_program] = is_program (),
     759                 :        600 :          [classify_shared] = is_shared (),
     760                 :        600 :          [classify_library] = is_library (),
     761                 :        600 :          [classify_linux_kernel_module] = is_linux_kernel_module (),
     762                 :        600 :          [classify_debug_only] = is_debug_only (),
     763                 :        600 :          [classify_loadable] = is_loadable (),
     764                 :            :         };
     765                 :            : 
     766         [ -  + ]:        600 :       if (verbose > 1)
     767                 :            :         {
     768         [ #  # ]:          0 :           if (checks[classify_elf])
     769                 :          0 :             fprintf (stderr, "debug: %s: elf\n", current_path);
     770         [ #  # ]:          0 :           if (checks[classify_elf_file])
     771                 :          0 :             fprintf (stderr, "debug: %s: elf_file\n", current_path);
     772         [ #  # ]:          0 :           if (checks[classify_elf_archive])
     773                 :          0 :             fprintf (stderr, "debug: %s: elf_archive\n", current_path);
     774         [ #  # ]:          0 :           if (checks[classify_core])
     775                 :          0 :             fprintf (stderr, "debug: %s: core\n", current_path);
     776         [ #  # ]:          0 :           if (checks[classify_unstripped])
     777                 :          0 :             fprintf (stderr, "debug: %s: unstripped\n", current_path);
     778         [ #  # ]:          0 :           if (checks[classify_executable])
     779                 :          0 :             fprintf (stderr, "debug: %s: executable\n", current_path);
     780         [ #  # ]:          0 :           if (checks[classify_program])
     781                 :          0 :             fprintf (stderr, "debug: %s: program\n", current_path);
     782         [ #  # ]:          0 :           if (checks[classify_shared])
     783                 :          0 :             fprintf (stderr, "debug: %s: shared\n", current_path);
     784         [ #  # ]:          0 :           if (checks[classify_library])
     785                 :          0 :             fprintf (stderr, "debug: %s: library\n", current_path);
     786         [ #  # ]:          0 :           if (checks[classify_linux_kernel_module])
     787                 :          0 :             fprintf (stderr, "debug: %s: linux kernel module\n", current_path);
     788         [ #  # ]:          0 :           if (checks[classify_debug_only])
     789                 :          0 :             fprintf (stderr, "debug: %s: debug-only\n", current_path);
     790         [ #  # ]:          0 :           if (checks[classify_loadable])
     791                 :          0 :             fprintf (stderr, "debug: %s: loadable\n", current_path);
     792                 :            :         }
     793                 :            : 
     794                 :        600 :       for (enum classify_check check = 0;
     795         [ +  + ]:       7800 :            check <= classify_check_last; ++check)
     796      [ +  +  + ]:       7200 :         switch (requirements[check])
     797                 :            :           {
     798                 :        856 :           case required:
     799         [ -  + ]:        856 :             if (!checks[check])
     800                 :          0 :               checks_passed = false;
     801                 :            :             break;
     802                 :        344 :           case forbidden:
     803         [ -  + ]:        344 :             if (checks[check])
     804                 :          0 :               checks_passed = false;
     805                 :            :             break;
     806                 :            :           case do_not_care:
     807                 :            :             break;
     808                 :            :           }
     809                 :       7200 :     }
     810         [ #  # ]:          0 :   else if (file_fd == -1)
     811                 :            :     checks_passed = false; /* There is nothing to check, bad file.  */
     812                 :            :   else
     813                 :            :     {
     814                 :          0 :       for (enum classify_check check = 0;
     815         [ #  # ]:          0 :            check <= classify_check_last; ++check)
     816         [ #  # ]:          0 :         if (requirements[check] == required)
     817                 :          0 :           checks_passed = false;
     818                 :            :     }
     819                 :            : 
     820                 :        600 :   close_elf ();
     821                 :            : 
     822   [ +  -  +  - ]:        600 :   switch (flag_print)
     823                 :            :     {
     824                 :        270 :     case do_print:
     825         [ +  - ]:        270 :       if (checks_passed == flag_print_matching)
     826                 :        270 :         puts (current_path);
     827                 :            :       break;
     828                 :          0 :     case do_print0:
     829         [ #  # ]:          0 :       if (checks_passed == flag_print_matching)
     830         [ #  # ]:          0 :         if (fwrite (current_path, strlen (current_path) + 1, 1, stdout) < 1)
     831                 :          0 :           issue (errno, N_("writing to standard output"));
     832                 :            :       break;
     833                 :        330 :     case no_print:
     834         [ -  + ]:        330 :       if (!checks_passed)
     835                 :          0 :         *status = 1;
     836                 :            :       break;
     837                 :            :     }
     838                 :        600 : }
     839                 :            : 
     840                 :            : /* Called to process standard input if flag_stdin is not no_stdin.  */
     841                 :            : static void
     842                 :          0 : process_stdin (int *status)
     843                 :            : {
     844                 :          0 :   char delim;
     845         [ #  # ]:          0 :   if (flag_stdin == do_stdin0)
     846                 :            :     delim = '\0';
     847                 :            :   else
     848                 :          0 :     delim = '\n';
     849                 :            : 
     850                 :          0 :   char *buffer = NULL;
     851                 :          0 :   size_t buffer_size = 0;
     852                 :          0 :   while (true)
     853                 :          0 :     {
     854                 :          0 :       ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
     855         [ #  # ]:          0 :       if (ferror (stdin))
     856                 :            :         {
     857                 :          0 :           current_path = NULL;
     858                 :          0 :           issue (errno, N_("reading from standard input"));
     859                 :          0 :           break;
     860                 :            :         }
     861         [ #  # ]:          0 :       if (feof (stdin))
     862                 :            :         break;
     863         [ #  # ]:          0 :       if (ret < 0)
     864                 :          0 :         abort ();           /* Cannot happen due to error checks above.  */
     865   [ #  #  #  # ]:          0 :       if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
     866                 :          0 :         buffer[ret - 1] = '\0';
     867                 :          0 :       current_path = buffer;
     868                 :          0 :       process_current_path (status);
     869                 :            :     }
     870                 :            : 
     871                 :          0 :   free (buffer);
     872                 :          0 : }
     873                 :            : 
     874                 :            : int
     875                 :        134 : main (int argc, char **argv)
     876                 :            : {
     877                 :        134 :   const struct argp_option options[] =
     878                 :            :     {
     879                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
     880                 :            :       { "elf", classify_check_offset + classify_elf, NULL, 0,
     881                 :            :         N_("File looks like an ELF object or archive/static library (default)")
     882                 :            :         , 1 },
     883                 :            :       { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
     884                 :            :         N_("File is an regular ELF object (not an archive/static library)")
     885                 :            :         , 1 },
     886                 :            :       { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
     887                 :            :         N_("File is an ELF archive or static library")
     888                 :            :         , 1 },
     889                 :            :       { "core", classify_check_offset + classify_core, NULL, 0,
     890                 :            :         N_("File is an ELF core dump file")
     891                 :            :         , 1 },
     892                 :            :       { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
     893                 :            :         N_("File is an ELF file with symbol table or .debug_* sections \
     894                 :            : and can be stripped further"), 1 },
     895                 :            :       { "executable", classify_check_offset + classify_executable, NULL, 0,
     896                 :            :         N_("File is (primarily) an ELF program executable \
     897                 :            : (not primarily a DSO)"), 1 },
     898                 :            :       { "program", classify_check_offset + classify_program, NULL, 0,
     899                 :            :         N_("File is an ELF program executable \
     900                 :            : (might also be a DSO)"), 1 },
     901                 :            :       { "shared", classify_check_offset + classify_shared, NULL, 0,
     902                 :            :         N_("File is (primarily) an ELF shared object (DSO) \
     903                 :            : (not primarily an executable)"), 1 },
     904                 :            :       { "library", classify_check_offset + classify_library, NULL, 0,
     905                 :            :         N_("File is an ELF shared object (DSO) \
     906                 :            : (might also be an executable)"), 1 },
     907                 :            :       { "linux-kernel-module", (classify_check_offset
     908                 :            :                                 + classify_linux_kernel_module), NULL, 0,
     909                 :            :         N_("File is a linux kernel module"), 1 },
     910                 :            :       { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
     911                 :            :         N_("File is a debug only ELF file \
     912                 :            : (separate .debug, .dwo or dwz multi-file)"), 1 },
     913                 :            :       { "loadable", classify_check_offset + classify_loadable, NULL, 0,
     914                 :            :         N_("File is a loadable ELF object (program or shared object)"), 1 },
     915                 :            : 
     916                 :            :       /* Negated versions of the above.  */
     917                 :            :       { "not-elf", classify_check_not_offset + classify_elf,
     918                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     919                 :            :       { "not-elf-file", classify_check_not_offset + classify_elf_file,
     920                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     921                 :            :       { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
     922                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     923                 :            :       { "not-core", classify_check_not_offset + classify_core,
     924                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     925                 :            :       { "not-unstripped", classify_check_not_offset + classify_unstripped,
     926                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     927                 :            :       { "not-executable", classify_check_not_offset + classify_executable,
     928                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     929                 :            :       { "not-program", classify_check_not_offset + classify_program,
     930                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     931                 :            :       { "not-shared", classify_check_not_offset + classify_shared,
     932                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     933                 :            :       { "not-library", classify_check_not_offset + classify_library,
     934                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     935                 :            :       { "not-linux-kernel-module", (classify_check_not_offset
     936                 :            :                                     + classify_linux_kernel_module),
     937                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     938                 :            :       { "not-debug-only", (classify_check_not_offset + classify_debug_only),
     939                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     940                 :            :       { "not-loadable", classify_check_not_offset + classify_loadable,
     941                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     942                 :            : 
     943                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
     944                 :            :       { "file", 'f', NULL, 0,
     945                 :            :         N_("Only classify regular (not symlink nor special device) files"), 2 },
     946                 :            :       { "stdin", classify_flag_stdin, NULL, 0,
     947                 :            :         N_("Also read file names to process from standard input, \
     948                 :            : separated by newlines"), 2 },
     949                 :            :       { "stdin0", classify_flag_stdin0, NULL, 0,
     950                 :            :         N_("Also read file names to process from standard input, \
     951                 :            : separated by ASCII NUL bytes"), 2 },
     952                 :            :       { "no-stdin", classify_flag_stdin, NULL, 0,
     953                 :            :         N_("Do not read files from standard input (default)"), 2 },
     954                 :            :       { "compressed", 'z', NULL, 0,
     955                 :            :         N_("Try to open compressed files or embedded (kernel) ELF images"),
     956                 :            :         2 },
     957                 :            : 
     958                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
     959                 :            :       { "print", classify_flag_print, NULL, 0,
     960                 :            :         N_("Output names of files, separated by newline"), 3 },
     961                 :            :       { "print0", classify_flag_print0, NULL, 0,
     962                 :            :         N_("Output names of files, separated by ASCII NUL"), 3 },
     963                 :            :       { "no-print", classify_flag_no_print, NULL, 0,
     964                 :            :         N_("Do not output file names"), 3 },
     965                 :            :       { "matching", classify_flag_matching, NULL, 0,
     966                 :            :         N_("If printing file names, print matching files (default)"), 3 },
     967                 :            :       { "not-matching", classify_flag_not_matching, NULL, 0,
     968                 :            :         N_("If printing file names, print files that do not match"), 3 },
     969                 :            : 
     970                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
     971                 :            :       { "verbose", 'v', NULL, 0,
     972                 :            :         N_("Output additional information (can be specified multiple times)"), 4 },
     973                 :            :       { "quiet", 'q', NULL, 0,
     974                 :            :         N_("Suppress some error output (counterpart to --verbose)"), 4 },
     975                 :            :       { NULL, 0, NULL, 0, NULL, 0 }
     976                 :            :     };
     977                 :            : 
     978                 :        134 :   const struct argp argp =
     979                 :            :     {
     980                 :            :       .options = options,
     981                 :            :       .parser = parse_opt,
     982                 :            :       .args_doc = N_("FILE..."),
     983                 :            :       .doc = N_("\
     984                 :            : Determine the type of an ELF file.\
     985                 :            : \n\n\
     986                 :            : All of the classification options must apply at the same time to a \
     987                 :            : particular file.  Classification options can be negated using a \
     988                 :            : \"--not-\" prefix.\
     989                 :            : \n\n\
     990                 :            : Since modern ELF does not clearly distinguish between programs and \
     991                 :            : dynamic shared objects, you should normally use either --executable or \
     992                 :            : --shared to identify the primary purpose of a file.  \
     993                 :            : Only one of the --shared and --executable checks can pass for a file.\
     994                 :            : \n\n\
     995                 :            : If you want to know whether an ELF object might a program or a \
     996                 :            : shared library (but could be both), then use --program or --library. \
     997                 :            : Some ELF files will classify as both a program and a library.\
     998                 :            : \n\n\
     999                 :            : If you just want to know whether an ELF file is loadable (as program \
    1000                 :            : or library) use --loadable.  Note that files that only contain \
    1001                 :            : (separate) debug information (--debug-only) are never --loadable (even \
    1002                 :            : though they might contain program headers).  Linux kernel modules are \
    1003                 :            : also not --loadable (in the normal sense).\
    1004                 :            : \n\n\
    1005                 :            : Without any of the --print options, the program exits with status 0 \
    1006                 :            : if the requested checks pass for all input files, with 1 if a check \
    1007                 :            : fails for any file, and 2 if there is an environmental issue (such \
    1008                 :            : as a file read error or a memory allocation error).\
    1009                 :            : \n\n\
    1010                 :            : When printing file names, the program exits with status 0 even if \
    1011                 :            : no file names are printed, and exits with status 2 if there is an \
    1012                 :            : environmental issue.\
    1013                 :            : \n\n\
    1014                 :            : On usage error (e.g. a bad option was given), the program exits with \
    1015                 :            : a status code larger than 2.\
    1016                 :            : \n\n\
    1017                 :            : The --quiet or -q option suppresses some error warning output, but \
    1018                 :            : doesn't change the exit status.\
    1019                 :            : ")
    1020                 :            :     };
    1021                 :            : 
    1022                 :            :   /* Require that the file is an ELF file by default.  User can
    1023                 :            :      disable with --not-elf.  */
    1024                 :        134 :   requirements[classify_elf] = required;
    1025                 :            : 
    1026                 :        134 :   int remaining;
    1027         [ +  - ]:        134 :   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
    1028                 :            :     return 2;
    1029                 :            : 
    1030                 :        134 :   elf_version (EV_CURRENT);
    1031                 :            : 
    1032                 :        134 :   int status = 0;
    1033                 :            : 
    1034         [ +  + ]:        734 :   for (int i = remaining; i < argc; ++i)
    1035                 :            :     {
    1036                 :        600 :       current_path = argv[i];
    1037                 :        600 :       process_current_path (&status);
    1038                 :            :     }
    1039                 :            : 
    1040         [ -  + ]:        134 :   if (flag_stdin != no_stdin)
    1041                 :          0 :     process_stdin (&status);
    1042                 :            : 
    1043         [ +  - ]:        134 :   if (issue_found)
    1044                 :            :     return 2;
    1045                 :            : 
    1046                 :        134 :   return status;
    1047                 :            : }

Generated by: LCOV version 1.14