LCOV - code coverage report
Current view: top level - src - elfclassify.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 223 406 54.9 %
Date: 2023-06-27 14:24:55 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                 :            : #include <system.h>
      20                 :            : 
      21                 :            : #include <argp.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         [ -  + ]:        600 :   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                 :            :     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         [ +  + ]:       4338 :     for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
     259                 :            :       {
     260                 :       3748 :         GElf_Phdr phdr_storage;
     261                 :       3748 :         GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
     262         [ -  + ]:       3748 :         if (phdr == NULL)
     263                 :            :           {
     264                 :          0 :             elf_issue (N_("program header"));
     265                 :          0 :             return false;
     266                 :            :           }
     267         [ +  + ]:       3748 :         if (phdr->p_type == PT_DYNAMIC)
     268                 :            :           {
     269                 :        252 :             dyn_seg = *phdr;
     270                 :        252 :             has_dynamic = true;
     271                 :            :           }
     272         [ +  + ]:       3748 :         if (phdr->p_type == PT_INTERP)
     273                 :        132 :           has_program_interpreter = true;
     274         [ +  + ]:       3748 :         if (phdr->p_type == PT_LOAD)
     275                 :       2098 :           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                 :      27198 :     while (true)
     301                 :      13304 :       {
     302                 :      13894 :         scn = elf_nextscn (elf, scn);
     303         [ +  + ]:      13894 :         if (scn == NULL)
     304                 :            :           break;
     305                 :      13304 :         GElf_Shdr shdr_storage;
     306                 :      13304 :         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
     307         [ -  + ]:      13304 :         if (shdr == NULL)
     308                 :            :           {
     309                 :          0 :             elf_issue (N_("could not obtain section header"));
     310                 :          0 :             return false;
     311                 :            :           }
     312                 :      13304 :         const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
     313         [ -  + ]:      13304 :         if (section_name == NULL)
     314                 :            :           {
     315                 :          0 :             elf_issue(N_("could not obtain section name"));
     316                 :          0 :             return false;
     317                 :            :           }
     318         [ -  + ]:      13304 :         if (verbose > 2)
     319                 :          0 :           fprintf (stderr, "debug: section header %s (type %d) found\n",
     320                 :            :                    section_name, shdr->sh_type);
     321         [ +  + ]:      13304 :         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                 :      13304 :         if (shdr->sh_type != SHT_NOBITS
     330         [ +  + ]:      13304 :             && shdr->sh_type != SHT_NOTE
     331         [ +  + ]:      10196 :             && (shdr->sh_flags & SHF_ALLOC) != 0)
     332                 :            :           {
     333   [ -  +  -  - ]:       4784 :             if (verbose > 1 && !has_bits_alloc)
     334                 :          0 :               fputs ("debug: allocated (non-nobits/note) section found\n",
     335                 :            :                      stderr);
     336                 :       4784 :             has_bits_alloc = true;
     337                 :            :           }
     338         [ +  + ]:      13304 :         if (startswith (section_name, ".debug_")
     339         [ +  + ]:      11376 :             || startswith (section_name, ".zdebug_"))
     340                 :            :           {
     341   [ -  +  -  - ]:       2334 :             if (verbose > 1 && !has_debug_sections)
     342                 :          0 :               fputs ("debug: .debug_* section found\n", stderr);
     343                 :       2334 :             has_debug_sections = true;
     344                 :            :           }
     345         [ +  + ]:      13304 :         if (strcmp (section_name, ".modinfo") == 0)
     346                 :            :           {
     347         [ -  + ]:         80 :             if (verbose > 1)
     348                 :          0 :               fputs ("debug: .modinfo section found\n", stderr);
     349                 :         80 :             has_modinfo = true;
     350                 :            :           }
     351         [ +  + ]:      13304 :         if (strcmp (section_name, ".gnu.linkonce.this_module") == 0)
     352                 :            :           {
     353         [ -  + ]:         80 :             if (verbose > 1)
     354                 :          0 :               fputs ("debug: .gnu.linkonce.this_module section found\n",
     355                 :            :                      stderr);
     356                 :         80 :             has_gnu_linkonce_this_module = true;
     357                 :            :           }
     358                 :            :       }
     359                 :            :   }
     360                 :            : 
     361                 :            :   /* Examine the dynamic section.  */
     362         [ +  + ]:        590 :   if (has_dynamic)
     363                 :            :     {
     364                 :        252 :       Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset,
     365                 :            :                                              dyn_seg.p_filesz,
     366                 :            :                                              ELF_T_DYN);
     367         [ +  + ]:        252 :       if (data != NULL)
     368                 :       5238 :         for (int dyn_idx = 0; ; ++dyn_idx)
     369                 :       5238 :           {
     370                 :       5478 :             GElf_Dyn dyn_storage;
     371                 :       5478 :             GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
     372         [ +  + ]:       5478 :             if (dyn == NULL)
     373                 :            :               break;
     374         [ -  + ]:       5426 :             if (verbose > 2)
     375                 :       5426 :               fprintf (stderr, "debug: dynamic entry %d"
     376                 :            :                        " with tag %llu found\n",
     377                 :          0 :                        dyn_idx, (unsigned long long int) dyn->d_tag);
     378         [ +  + ]:       5426 :             if (dyn->d_tag == DT_SONAME)
     379                 :         16 :               has_soname = true;
     380   [ +  +  +  - ]:       5426 :             if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
     381                 :         32 :               has_pie_flag = true;
     382         [ +  + ]:       5426 :             if (dyn->d_tag == DT_DEBUG)
     383                 :         72 :               has_dt_debug = true;
     384         [ +  + ]:       5426 :             if (dyn->d_tag == DT_NULL)
     385                 :            :               break;
     386                 :            :           }
     387                 :            :     }
     388                 :            : 
     389         [ +  - ]:        590 :   if (verbose > 0)
     390                 :            :     {
     391                 :          0 :       fprintf (stderr, "info: %s: ELF type: %s (0x%x)\n", current_path,
     392                 :            :                elf_type_string (elf_type), elf_type);
     393         [ #  # ]:          0 :       if (has_program_load)
     394                 :          0 :         fprintf (stderr, "info: %s: PT_LOAD found\n", current_path);
     395         [ #  # ]:          0 :       if (has_sections)
     396                 :          0 :         fprintf (stderr, "info: %s: has sections\n", current_path);
     397         [ #  # ]:          0 :       if (has_bits_alloc)
     398                 :          0 :         fprintf (stderr, "info: %s: allocated (real) section found\n",
     399                 :            :                  current_path);
     400         [ #  # ]:          0 :       if (has_program_interpreter)
     401                 :          0 :         fprintf (stderr, "info: %s: program interpreter found\n",
     402                 :            :                  current_path);
     403         [ #  # ]:          0 :       if (has_dynamic)
     404                 :          0 :         fprintf (stderr, "info: %s: dynamic segment found\n", current_path);
     405         [ #  # ]:          0 :       if (has_soname)
     406                 :          0 :         fprintf (stderr, "info: %s: soname found\n", current_path);
     407         [ #  # ]:          0 :       if (has_pie_flag)
     408                 :          0 :         fprintf (stderr, "info: %s: DF_1_PIE flag found\n", current_path);
     409         [ #  # ]:          0 :       if (has_dt_debug)
     410                 :          0 :         fprintf (stderr, "info: %s: DT_DEBUG found\n", current_path);
     411         [ #  # ]:          0 :       if (has_symtab)
     412                 :          0 :         fprintf (stderr, "info: %s: symbol table found\n", current_path);
     413         [ #  # ]:          0 :       if (has_debug_sections)
     414                 :          0 :         fprintf (stderr, "info: %s: .debug_* section found\n", current_path);
     415         [ #  # ]:          0 :       if (has_modinfo)
     416                 :          0 :         fprintf (stderr, "info: %s: .modinfo section found\n", current_path);
     417         [ #  # ]:          0 :       if (has_gnu_linkonce_this_module)
     418                 :          0 :         fprintf (stderr,
     419                 :            :                  "info: %s: .gnu.linkonce.this_module section found\n",
     420                 :            :                  current_path);
     421                 :            :     }
     422                 :            : 
     423                 :            :   return true;
     424                 :            : }
     425                 :            : 
     426                 :            : static bool
     427                 :        600 : is_elf (void)
     428                 :            : {
     429                 :        600 :   return elf_kind (elf) != ELF_K_NONE;
     430                 :            : }
     431                 :            : 
     432                 :            : static bool
     433                 :        600 : is_elf_file (void)
     434                 :            : {
     435                 :        600 :   return elf_kind (elf) == ELF_K_ELF;
     436                 :            : }
     437                 :            : 
     438                 :            : static bool
     439                 :        600 : is_elf_archive (void)
     440                 :            : {
     441                 :        600 :   return elf_kind (elf) == ELF_K_AR;
     442                 :            : }
     443                 :            : 
     444                 :            : static bool
     445                 :        600 : is_core (void)
     446                 :            : {
     447   [ +  +  +  + ]:        600 :   return elf_kind (elf) == ELF_K_ELF && elf_type == ET_CORE;
     448                 :            : }
     449                 :            : 
     450                 :            : /* Return true if the file is a loadable object, which basically means
     451                 :            :    it is an ELF file, but not a relocatable object or a core dump
     452                 :            :    file.  (The kernel and various userspace components can load ET_REL
     453                 :            :    files, but we disregard that for our classification purposes.)  */
     454                 :            : static bool
     455                 :       2814 : is_loadable (void)
     456                 :            : {
     457                 :       2814 :   return elf_kind (elf) == ELF_K_ELF
     458         [ +  + ]:       2774 :     && (elf_type == ET_EXEC || elf_type == ET_DYN)
     459         [ +  - ]:       1582 :     && has_program_load
     460   [ +  +  +  +  :       4396 :     && (!has_sections || has_bits_alloc); /* It isn't debug-only.  */
                   +  + ]
     461                 :            : }
     462                 :            : 
     463                 :            : /* Return true if the file is an ELF file which has a symbol table or
     464                 :            :    .debug_* sections (and thus can be stripped further).  */
     465                 :            : static bool
     466                 :        600 : is_unstripped (void)
     467                 :            : {
     468                 :        600 :   return elf_kind (elf) != ELF_K_NONE
     469         [ +  + ]:        600 :     && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
     470   [ +  -  +  +  :       1090 :     && (has_symtab || has_debug_sections);
                   -  + ]
     471                 :            : }
     472                 :            : 
     473                 :            : /* Return true if the file contains only debuginfo, but no loadable
     474                 :            :    program bits.  Then it is most likely a separate .debug file, a dwz
     475                 :            :    multi-file or a .dwo file.  Note that it can still be loadable,
     476                 :            :    but in that case the phdrs shouldn't be trusted.  */
     477                 :            : static bool
     478                 :        600 : is_debug_only (void)
     479                 :            : {
     480                 :        600 :   return elf_kind (elf) != ELF_K_NONE
     481         [ +  + ]:        600 :     && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
     482   [ +  +  +  + ]:        490 :     && (has_debug_sections || has_symtab)
     483   [ +  -  +  + ]:       1030 :     && !has_bits_alloc;
     484                 :            : }
     485                 :            : 
     486                 :            : static bool
     487                 :        808 : is_shared (void)
     488                 :            : {
     489         [ +  + ]:        808 :   if (!is_loadable ())
     490                 :            :     return false;
     491                 :            : 
     492                 :            :   /* The ELF type is very clear: this is an executable.  */
     493         [ +  + ]:        416 :   if (elf_type == ET_EXEC)
     494                 :            :     return false;
     495                 :            : 
     496                 :            :   /* If there is no dynamic section, the file cannot be loaded as a
     497                 :            :      shared object.  */
     498         [ +  - ]:        316 :   if (!has_dynamic)
     499                 :            :     return false;
     500                 :            : 
     501                 :            :   /* If the object is marked as PIE, it is definitely an executable,
     502                 :            :      and not a loadlable shared object.  */
     503         [ +  + ]:        316 :   if (has_pie_flag)
     504                 :            :     return false;
     505                 :            : 
     506                 :            :   /* Treat a DT_SONAME tag as a strong indicator that this is a shared
     507                 :            :      object.  */
     508         [ +  + ]:        252 :   if (has_soname)
     509                 :            :     return true;
     510                 :            : 
     511                 :            :   /* This is probably a PIE program: there is no soname, but a program
     512                 :            :      interpreter.  In theory, this file could be also a DSO with a
     513                 :            :      soname implied by its file name that can be run as a program.
     514                 :            :      This situation is impossible to resolve in the general case. */
     515         [ +  + ]:        220 :   if (has_program_interpreter)
     516                 :            :     return false;
     517                 :            : 
     518                 :            :   /* Roland McGrath mentions in
     519                 :            :      <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
     520                 :            :      that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
     521                 :            :      matches current binutils behavior (version 2.32).  DT_DEBUG is
     522                 :            :      added if bfd_link_executable returns true or if bfd_link_pic
     523                 :            :      returns false, depending on the architectures.  However, DT_DEBUG
     524                 :            :      is not documented as being specific to executables, therefore use
     525                 :            :      it only as a low-priority discriminator.  */
     526         [ -  + ]:        160 :   if (has_dt_debug)
     527                 :          0 :     return false;
     528                 :            : 
     529                 :            :   return true;
     530                 :            : }
     531                 :            : 
     532                 :            : static bool
     533                 :        600 : is_executable (void)
     534                 :            : {
     535         [ +  + ]:        600 :   if (!is_loadable ())
     536                 :            :     return false;
     537                 :            : 
     538                 :            :   /* A loadable object which is not a shared object is treated as an
     539                 :            :      executable.  */
     540                 :        208 :   return !is_shared ();
     541                 :            : }
     542                 :            : 
     543                 :            : /* Like is_executable, but the object can also be a shared library at
     544                 :            :    the same time.  */
     545                 :            : static bool
     546                 :        600 : is_program (void)
     547                 :            : {
     548         [ +  + ]:        600 :   if (!is_loadable ())
     549                 :            :     return false;
     550                 :            : 
     551                 :            :   /* The ELF type is very clear: this is an executable.  */
     552         [ +  + ]:        208 :   if (elf_type == ET_EXEC)
     553                 :            :     return true;
     554                 :            : 
     555                 :            :   /* If the object is marked as PIE, it is definitely an executable,
     556                 :            :      and not a loadlable shared object.  */
     557         [ +  + ]:        158 :   if (has_pie_flag)
     558                 :            :     return true;
     559                 :            : 
     560                 :            :   /* This is probably a PIE program. It isn't ET_EXEC, but has a
     561                 :            :      program interpreter. In theory, this file could be also a DSO
     562                 :            :      with a soname. This situation is impossible to resolve in the
     563                 :            :      general case. See is_shared. This is different from
     564                 :            :      is_executable.  */
     565         [ +  + ]:        126 :   if (has_program_interpreter)
     566                 :            :     return true;
     567                 :            : 
     568                 :            :   /* Roland McGrath mentions in
     569                 :            :      <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
     570                 :            :      that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
     571                 :            :      matches current binutils behavior (version 2.32).  DT_DEBUG is
     572                 :            :      added if bfd_link_executable returns true or if bfd_link_pic
     573                 :            :      returns false, depending on the architectures.  However, DT_DEBUG
     574                 :            :      is not documented as being specific to executables, therefore use
     575                 :            :      it only as a low-priority discriminator.  */
     576                 :         96 :   if (has_dt_debug)
     577                 :            :     return true;
     578                 :            : 
     579                 :            :   return false;
     580                 :            : }
     581                 :            : 
     582                 :            : /* Like is_shared but the library could also be an executable.  */
     583                 :            : static bool
     584                 :        600 : is_library  (void)
     585                 :            : {
     586                 :            :   /* Only ET_DYN can be shared libraries.  */
     587         [ +  + ]:        600 :   if (elf_type != ET_DYN)
     588                 :            :     return false;
     589                 :            : 
     590         [ +  + ]:        206 :   if (!is_loadable ())
     591                 :            :     return false;
     592                 :            : 
     593                 :            :   /* Without a PT_DYNAMIC segment the library cannot be loaded.  */
     594         [ +  - ]:        158 :   if (!has_dynamic)
     595                 :            :     return false;
     596                 :            : 
     597                 :            :   /* This really is a (PIE) executable.  See is_shared.  */
     598   [ +  +  +  + ]:        158 :   if (has_pie_flag || has_dt_debug)
     599                 :         62 :     return false;
     600                 :            : 
     601                 :            :   /* It could still (also) be a (PIE) executable, but most likely you
     602                 :            :      can dlopen it just fine.  */
     603                 :            :   return true;
     604                 :            : }
     605                 :            : 
     606                 :            : /* Returns true if the file is a linux kernel module (is ET_REL and
     607                 :            :    has the two magic sections .modinfo and .gnu.linkonce.this_module).  */
     608                 :            : static bool
     609                 :        600 : is_linux_kernel_module (void)
     610                 :            : {
     611                 :        600 :   return (elf_kind (elf) == ELF_K_ELF
     612         [ +  + ]:        590 :           && elf_type == ET_REL
     613         [ +  + ]:        198 :           && has_modinfo
     614   [ +  +  -  + ]:        680 :           && has_gnu_linkonce_this_module);
     615                 :            : }
     616                 :            : 
     617                 :            : enum classify_requirement { do_not_care, required, forbidden };
     618                 :            : 
     619                 :            : enum classify_check
     620                 :            : {
     621                 :            :   classify_elf,
     622                 :            :   classify_elf_file,
     623                 :            :   classify_elf_archive,
     624                 :            :   classify_core,
     625                 :            :   classify_unstripped,
     626                 :            :   classify_executable,
     627                 :            :   classify_program,
     628                 :            :   classify_shared,
     629                 :            :   classify_library,
     630                 :            :   classify_linux_kernel_module,
     631                 :            :   classify_debug_only,
     632                 :            :   classify_loadable,
     633                 :            : 
     634                 :            :   classify_check_last = classify_loadable
     635                 :            : };
     636                 :            : 
     637                 :            : enum
     638                 :            : {
     639                 :            :   classify_check_offset = 1000,
     640                 :            :   classify_check_not_offset = 2000,
     641                 :            : 
     642                 :            :   classify_flag_stdin = 3000,
     643                 :            :   classify_flag_stdin0,
     644                 :            :   classify_flag_no_stdin,
     645                 :            :   classify_flag_print,
     646                 :            :   classify_flag_print0,
     647                 :            :   classify_flag_no_print,
     648                 :            :   classify_flag_matching,
     649                 :            :   classify_flag_not_matching,
     650                 :            : };
     651                 :            : 
     652                 :            : static bool
     653                 :        842 : classify_check_positive (int key)
     654                 :            : {
     655                 :        842 :   return key >= classify_check_offset
     656                 :        842 :     && key <= classify_check_offset + classify_check_last;
     657                 :            : }
     658                 :            : 
     659                 :            : static bool
     660                 :        782 : classify_check_negative (int key)
     661                 :            : {
     662                 :        782 :   return key >= classify_check_not_offset
     663                 :        782 :     && key <= classify_check_not_offset + classify_check_last;
     664                 :            : }
     665                 :            : 
     666                 :            : /* Set by parse_opt.  */
     667                 :            : static enum classify_requirement requirements[classify_check_last + 1];
     668                 :            : static enum { no_stdin, do_stdin, do_stdin0 } flag_stdin;
     669                 :            : static enum { no_print, do_print, do_print0 } flag_print;
     670                 :            : static bool flag_print_matching = true;
     671                 :            : 
     672                 :            : static error_t
     673                 :        842 : parse_opt (int key, char *arg __attribute__ ((unused)),
     674                 :            :            struct argp_state *state __attribute__ ((unused)))
     675                 :            : {
     676         [ +  + ]:        842 :   if (classify_check_positive (key))
     677                 :         60 :     requirements[key - classify_check_offset] = required;
     678         [ +  + ]:        782 :   else if (classify_check_negative (key))
     679                 :         74 :     requirements[key - classify_check_not_offset] = forbidden;
     680                 :            :   else
     681   [ -  -  -  -  :        708 :     switch (key)
          -  -  -  +  -  
             -  -  -  + ]
     682                 :            :       {
     683                 :          0 :       case 'v':
     684                 :          0 :         ++verbose;
     685                 :          0 :         break;
     686                 :            : 
     687                 :          0 :       case 'q':
     688                 :          0 :         --verbose;
     689                 :          0 :         break;
     690                 :            : 
     691                 :          0 :       case 'z':
     692                 :          0 :         flag_compressed = true;
     693                 :          0 :         break;
     694                 :            : 
     695                 :          0 :       case 'f':
     696                 :          0 :         flag_only_regular_files = true;
     697                 :          0 :         break;
     698                 :            : 
     699                 :          0 :       case classify_flag_stdin:
     700                 :          0 :         flag_stdin = do_stdin;
     701                 :          0 :         break;
     702                 :            : 
     703                 :          0 :       case classify_flag_stdin0:
     704                 :          0 :         flag_stdin = do_stdin0;
     705                 :          0 :         break;
     706                 :            : 
     707                 :          0 :       case classify_flag_no_stdin:
     708                 :          0 :         flag_stdin = no_stdin;
     709                 :          0 :         break;
     710                 :            : 
     711                 :         38 :       case classify_flag_print:
     712                 :         38 :         flag_print = do_print;
     713                 :         38 :         break;
     714                 :            : 
     715                 :          0 :       case classify_flag_print0:
     716                 :          0 :         flag_print = do_print0;
     717                 :          0 :         break;
     718                 :            : 
     719                 :          0 :       case classify_flag_no_print:
     720                 :          0 :         flag_print = no_print;
     721                 :          0 :         break;
     722                 :            : 
     723                 :          0 :       case classify_flag_matching:
     724                 :          0 :         flag_print_matching = true;
     725                 :          0 :         break;
     726                 :            : 
     727                 :          0 :       case classify_flag_not_matching:
     728                 :          0 :         flag_print_matching = false;
     729                 :          0 :         break;
     730                 :            : 
     731                 :            :       default:
     732                 :            :         return ARGP_ERR_UNKNOWN;
     733                 :            :       }
     734                 :            : 
     735                 :            :   return 0;
     736                 :            : }
     737                 :            : 
     738                 :            : /* Perform requested checks against the file at current_path.  If
     739                 :            :    necessary, sets *STATUS to 1 if checks failed.  */
     740                 :            : static void
     741                 :        600 : process_current_path (int *status)
     742                 :            : {
     743                 :        600 :   bool checks_passed = true;
     744                 :            : 
     745   [ +  -  +  - ]:        600 :   if (open_elf () && run_classify ())
     746                 :        600 :     {
     747                 :        600 :       bool checks[] =
     748                 :            :         {
     749                 :            :          [classify_elf] = is_elf (),
     750                 :            :          [classify_elf_file] = is_elf_file (),
     751                 :            :          [classify_elf_archive] = is_elf_archive (),
     752                 :        600 :          [classify_core] = is_core (),
     753                 :        600 :          [classify_unstripped] = is_unstripped (),
     754                 :        600 :          [classify_executable] = is_executable (),
     755                 :        600 :          [classify_program] = is_program (),
     756                 :        600 :          [classify_shared] = is_shared (),
     757                 :        600 :          [classify_library] = is_library (),
     758                 :        600 :          [classify_linux_kernel_module] = is_linux_kernel_module (),
     759                 :        600 :          [classify_debug_only] = is_debug_only (),
     760                 :        600 :          [classify_loadable] = is_loadable (),
     761                 :            :         };
     762                 :            : 
     763         [ -  + ]:        600 :       if (verbose > 1)
     764                 :            :         {
     765         [ #  # ]:          0 :           if (checks[classify_elf])
     766                 :          0 :             fprintf (stderr, "debug: %s: elf\n", current_path);
     767         [ #  # ]:          0 :           if (checks[classify_elf_file])
     768                 :          0 :             fprintf (stderr, "debug: %s: elf_file\n", current_path);
     769         [ #  # ]:          0 :           if (checks[classify_elf_archive])
     770                 :          0 :             fprintf (stderr, "debug: %s: elf_archive\n", current_path);
     771         [ #  # ]:          0 :           if (checks[classify_core])
     772                 :          0 :             fprintf (stderr, "debug: %s: core\n", current_path);
     773         [ #  # ]:          0 :           if (checks[classify_unstripped])
     774                 :          0 :             fprintf (stderr, "debug: %s: unstripped\n", current_path);
     775         [ #  # ]:          0 :           if (checks[classify_executable])
     776                 :          0 :             fprintf (stderr, "debug: %s: executable\n", current_path);
     777         [ #  # ]:          0 :           if (checks[classify_program])
     778                 :          0 :             fprintf (stderr, "debug: %s: program\n", current_path);
     779         [ #  # ]:          0 :           if (checks[classify_shared])
     780                 :          0 :             fprintf (stderr, "debug: %s: shared\n", current_path);
     781         [ #  # ]:          0 :           if (checks[classify_library])
     782                 :          0 :             fprintf (stderr, "debug: %s: library\n", current_path);
     783         [ #  # ]:          0 :           if (checks[classify_linux_kernel_module])
     784                 :          0 :             fprintf (stderr, "debug: %s: linux kernel module\n", current_path);
     785         [ #  # ]:          0 :           if (checks[classify_debug_only])
     786                 :          0 :             fprintf (stderr, "debug: %s: debug-only\n", current_path);
     787         [ #  # ]:          0 :           if (checks[classify_loadable])
     788                 :          0 :             fprintf (stderr, "debug: %s: loadable\n", current_path);
     789                 :            :         }
     790                 :            : 
     791                 :        600 :       for (enum classify_check check = 0;
     792         [ +  + ]:       7800 :            check <= classify_check_last; ++check)
     793      [ +  +  + ]:       7200 :         switch (requirements[check])
     794                 :            :           {
     795                 :        856 :           case required:
     796         [ +  - ]:        856 :             if (!checks[check])
     797                 :       7200 :               checks_passed = false;
     798                 :            :             break;
     799                 :        344 :           case forbidden:
     800         [ +  - ]:        344 :             if (checks[check])
     801                 :       7200 :               checks_passed = false;
     802                 :            :             break;
     803                 :            :           case do_not_care:
     804                 :            :             break;
     805                 :            :           }
     806                 :            :     }
     807         [ #  # ]:          0 :   else if (file_fd == -1)
     808                 :            :     checks_passed = false; /* There is nothing to check, bad file.  */
     809                 :            :   else
     810                 :            :     {
     811                 :            :       for (enum classify_check check = 0;
     812         [ #  # ]:          0 :            check <= classify_check_last; ++check)
     813         [ #  # ]:          0 :         if (requirements[check] == required)
     814                 :          0 :           checks_passed = false;
     815                 :            :     }
     816                 :            : 
     817                 :        600 :   close_elf ();
     818                 :            : 
     819   [ +  -  +  - ]:        600 :   switch (flag_print)
     820                 :            :     {
     821                 :        270 :     case do_print:
     822         [ +  - ]:        270 :       if (checks_passed == flag_print_matching)
     823                 :        270 :         puts (current_path);
     824                 :            :       break;
     825                 :          0 :     case do_print0:
     826         [ #  # ]:          0 :       if (checks_passed == flag_print_matching)
     827         [ #  # ]:          0 :         if (fwrite (current_path, strlen (current_path) + 1, 1, stdout) < 1)
     828                 :          0 :           issue (errno, N_("writing to standard output"));
     829                 :            :       break;
     830                 :        330 :     case no_print:
     831         [ -  + ]:        330 :       if (!checks_passed)
     832                 :          0 :         *status = 1;
     833                 :            :       break;
     834                 :            :     }
     835                 :        600 : }
     836                 :            : 
     837                 :            : /* Called to process standard input if flag_stdin is not no_stdin.  */
     838                 :            : static void
     839                 :          0 : process_stdin (int *status)
     840                 :            : {
     841                 :          0 :   char delim;
     842         [ #  # ]:          0 :   if (flag_stdin == do_stdin0)
     843                 :            :     delim = '\0';
     844                 :            :   else
     845                 :          0 :     delim = '\n';
     846                 :            : 
     847                 :          0 :   char *buffer = NULL;
     848                 :          0 :   size_t buffer_size = 0;
     849                 :          0 :   while (true)
     850                 :          0 :     {
     851                 :          0 :       ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
     852         [ #  # ]:          0 :       if (ferror (stdin))
     853                 :            :         {
     854                 :          0 :           current_path = NULL;
     855                 :          0 :           issue (errno, N_("reading from standard input"));
     856                 :          0 :           break;
     857                 :            :         }
     858         [ #  # ]:          0 :       if (feof (stdin))
     859                 :            :         break;
     860         [ #  # ]:          0 :       if (ret < 0)
     861                 :          0 :         abort ();           /* Cannot happen due to error checks above.  */
     862   [ #  #  #  # ]:          0 :       if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
     863                 :          0 :         buffer[ret - 1] = '\0';
     864                 :          0 :       current_path = buffer;
     865                 :          0 :       process_current_path (status);
     866                 :            :     }
     867                 :            : 
     868                 :          0 :   free (buffer);
     869                 :          0 : }
     870                 :            : 
     871                 :            : int
     872                 :        134 : main (int argc, char **argv)
     873                 :            : {
     874                 :        134 :   const struct argp_option options[] =
     875                 :            :     {
     876                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
     877                 :            :       { "elf", classify_check_offset + classify_elf, NULL, 0,
     878                 :            :         N_("File looks like an ELF object or archive/static library (default)")
     879                 :            :         , 1 },
     880                 :            :       { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
     881                 :            :         N_("File is an regular ELF object (not an archive/static library)")
     882                 :            :         , 1 },
     883                 :            :       { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
     884                 :            :         N_("File is an ELF archive or static library")
     885                 :            :         , 1 },
     886                 :            :       { "core", classify_check_offset + classify_core, NULL, 0,
     887                 :            :         N_("File is an ELF core dump file")
     888                 :            :         , 1 },
     889                 :            :       { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
     890                 :            :         N_("File is an ELF file with symbol table or .debug_* sections \
     891                 :            : and can be stripped further"), 1 },
     892                 :            :       { "executable", classify_check_offset + classify_executable, NULL, 0,
     893                 :            :         N_("File is (primarily) an ELF program executable \
     894                 :            : (not primarily a DSO)"), 1 },
     895                 :            :       { "program", classify_check_offset + classify_program, NULL, 0,
     896                 :            :         N_("File is an ELF program executable \
     897                 :            : (might also be a DSO)"), 1 },
     898                 :            :       { "shared", classify_check_offset + classify_shared, NULL, 0,
     899                 :            :         N_("File is (primarily) an ELF shared object (DSO) \
     900                 :            : (not primarily an executable)"), 1 },
     901                 :            :       { "library", classify_check_offset + classify_library, NULL, 0,
     902                 :            :         N_("File is an ELF shared object (DSO) \
     903                 :            : (might also be an executable)"), 1 },
     904                 :            :       { "linux-kernel-module", (classify_check_offset
     905                 :            :                                 + classify_linux_kernel_module), NULL, 0,
     906                 :            :         N_("File is a linux kernel module"), 1 },
     907                 :            :       { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
     908                 :            :         N_("File is a debug only ELF file \
     909                 :            : (separate .debug, .dwo or dwz multi-file)"), 1 },
     910                 :            :       { "loadable", classify_check_offset + classify_loadable, NULL, 0,
     911                 :            :         N_("File is a loadable ELF object (program or shared object)"), 1 },
     912                 :            : 
     913                 :            :       /* Negated versions of the above.  */
     914                 :            :       { "not-elf", classify_check_not_offset + classify_elf,
     915                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     916                 :            :       { "not-elf-file", classify_check_not_offset + classify_elf_file,
     917                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     918                 :            :       { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
     919                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     920                 :            :       { "not-core", classify_check_not_offset + classify_core,
     921                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     922                 :            :       { "not-unstripped", classify_check_not_offset + classify_unstripped,
     923                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     924                 :            :       { "not-executable", classify_check_not_offset + classify_executable,
     925                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     926                 :            :       { "not-program", classify_check_not_offset + classify_program,
     927                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     928                 :            :       { "not-shared", classify_check_not_offset + classify_shared,
     929                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     930                 :            :       { "not-library", classify_check_not_offset + classify_library,
     931                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     932                 :            :       { "not-linux-kernel-module", (classify_check_not_offset
     933                 :            :                                     + classify_linux_kernel_module),
     934                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     935                 :            :       { "not-debug-only", (classify_check_not_offset + classify_debug_only),
     936                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     937                 :            :       { "not-loadable", classify_check_not_offset + classify_loadable,
     938                 :            :         NULL, OPTION_HIDDEN, NULL, 1 },
     939                 :            : 
     940                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
     941                 :            :       { "file", 'f', NULL, 0,
     942                 :            :         N_("Only classify regular (not symlink nor special device) files"), 2 },
     943                 :            :       { "stdin", classify_flag_stdin, NULL, 0,
     944                 :            :         N_("Also read file names to process from standard input, \
     945                 :            : separated by newlines"), 2 },
     946                 :            :       { "stdin0", classify_flag_stdin0, NULL, 0,
     947                 :            :         N_("Also read file names to process from standard input, \
     948                 :            : separated by ASCII NUL bytes"), 2 },
     949                 :            :       { "no-stdin", classify_flag_no_stdin, NULL, 0,
     950                 :            :         N_("Do not read files from standard input (default)"), 2 },
     951                 :            :       { "compressed", 'z', NULL, 0,
     952                 :            :         N_("Try to open compressed files or embedded (kernel) ELF images"),
     953                 :            :         2 },
     954                 :            : 
     955                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
     956                 :            :       { "print", classify_flag_print, NULL, 0,
     957                 :            :         N_("Output names of files, separated by newline"), 3 },
     958                 :            :       { "print0", classify_flag_print0, NULL, 0,
     959                 :            :         N_("Output names of files, separated by ASCII NUL"), 3 },
     960                 :            :       { "no-print", classify_flag_no_print, NULL, 0,
     961                 :            :         N_("Do not output file names"), 3 },
     962                 :            :       { "matching", classify_flag_matching, NULL, 0,
     963                 :            :         N_("If printing file names, print matching files (default)"), 3 },
     964                 :            :       { "not-matching", classify_flag_not_matching, NULL, 0,
     965                 :            :         N_("If printing file names, print files that do not match"), 3 },
     966                 :            : 
     967                 :            :       { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
     968                 :            :       { "verbose", 'v', NULL, 0,
     969                 :            :         N_("Output additional information (can be specified multiple times)"), 4 },
     970                 :            :       { "quiet", 'q', NULL, 0,
     971                 :            :         N_("Suppress some error output (counterpart to --verbose)"), 4 },
     972                 :            :       { NULL, 0, NULL, 0, NULL, 0 }
     973                 :            :     };
     974                 :            : 
     975                 :        134 :   const struct argp argp =
     976                 :            :     {
     977                 :            :       .options = options,
     978                 :            :       .parser = parse_opt,
     979                 :            :       .args_doc = N_("FILE..."),
     980                 :            :       .doc = N_("\
     981                 :            : Determine the type of an ELF file.\
     982                 :            : \n\n\
     983                 :            : All of the classification options must apply at the same time to a \
     984                 :            : particular file.  Classification options can be negated using a \
     985                 :            : \"--not-\" prefix.\
     986                 :            : \n\n\
     987                 :            : Since modern ELF does not clearly distinguish between programs and \
     988                 :            : dynamic shared objects, you should normally use either --executable or \
     989                 :            : --shared to identify the primary purpose of a file.  \
     990                 :            : Only one of the --shared and --executable checks can pass for a file.\
     991                 :            : \n\n\
     992                 :            : If you want to know whether an ELF object might a program or a \
     993                 :            : shared library (but could be both), then use --program or --library. \
     994                 :            : Some ELF files will classify as both a program and a library.\
     995                 :            : \n\n\
     996                 :            : If you just want to know whether an ELF file is loadable (as program \
     997                 :            : or library) use --loadable.  Note that files that only contain \
     998                 :            : (separate) debug information (--debug-only) are never --loadable (even \
     999                 :            : though they might contain program headers).  Linux kernel modules are \
    1000                 :            : also not --loadable (in the normal sense).\
    1001                 :            : \n\n\
    1002                 :            : Without any of the --print options, the program exits with status 0 \
    1003                 :            : if the requested checks pass for all input files, with 1 if a check \
    1004                 :            : fails for any file, and 2 if there is an environmental issue (such \
    1005                 :            : as a file read error or a memory allocation error).\
    1006                 :            : \n\n\
    1007                 :            : When printing file names, the program exits with status 0 even if \
    1008                 :            : no file names are printed, and exits with status 2 if there is an \
    1009                 :            : environmental issue.\
    1010                 :            : \n\n\
    1011                 :            : On usage error (e.g. a bad option was given), the program exits with \
    1012                 :            : a status code larger than 2.\
    1013                 :            : \n\n\
    1014                 :            : The --quiet or -q option suppresses some error warning output, but \
    1015                 :            : doesn't change the exit status.\
    1016                 :            : ")
    1017                 :            :     };
    1018                 :            : 
    1019                 :            :   /* Require that the file is an ELF file by default.  User can
    1020                 :            :      disable with --not-elf.  */
    1021                 :        134 :   requirements[classify_elf] = required;
    1022                 :            : 
    1023                 :        134 :   int remaining;
    1024         [ -  + ]:        134 :   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
    1025                 :            :     return 2;
    1026                 :            : 
    1027                 :        134 :   elf_version (EV_CURRENT);
    1028                 :            : 
    1029                 :        134 :   int status = 0;
    1030                 :            : 
    1031         [ +  + ]:        734 :   for (int i = remaining; i < argc; ++i)
    1032                 :            :     {
    1033                 :        600 :       current_path = argv[i];
    1034                 :        600 :       process_current_path (&status);
    1035                 :            :     }
    1036                 :            : 
    1037         [ -  + ]:        134 :   if (flag_stdin != no_stdin)
    1038                 :          0 :     process_stdin (&status);
    1039                 :            : 
    1040         [ -  + ]:        134 :   if (issue_found)
    1041                 :            :     return 2;
    1042                 :            : 
    1043                 :        134 :   return status;
    1044                 :            : }

Generated by: LCOV version 1.16