LCOV - code coverage report
Current view: top level - src - elfclassify.c (source / functions) Coverage Total Hit
Test: elfutils-0.193 Lines: 55.8 % 466 260
Test Date: 2025-08-30 14:31:09 Functions: 80.0 % 25 20
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 53.3 % 360 192

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

Generated by: LCOV version 2.0-1