Blame src/elfclassify.c

Packit Service 97d2fb
/* Classification of ELF files.
Packit Service 97d2fb
   Copyright (C) 2019 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#include <config.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <error.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <gelf.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stddef.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <sys/stat.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include ELFUTILS_HEADER(elf)
Packit Service 97d2fb
#include ELFUTILS_HEADER(dwelf)
Packit Service 97d2fb
#include "printversion.h"
Packit Service 97d2fb
Packit Service 97d2fb
/* Name and version of program.  */
Packit Service 97d2fb
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit Service 97d2fb
Packit Service 97d2fb
/* Bug report address.  */
Packit Service 97d2fb
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by parse_opt.  */
Packit Service 97d2fb
static int verbose;
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by the main function.  */
Packit Service 97d2fb
static const char *current_path;
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by open_file.  */
Packit Service 97d2fb
static int file_fd = -1;
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by issue or elf_issue.  */
Packit Service 97d2fb
static bool issue_found;
Packit Service 97d2fb
Packit Service 97d2fb
/* Non-fatal issue occured while processing the current_path.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
issue (int e, const char *msg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (verbose >= 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (current_path == NULL)
Packit Service 97d2fb
	error (0, e, "%s", msg);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	error (0, e, "%s '%s'", msg, current_path);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  issue_found = true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Non-fatal issue occured while processing the current ELF.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
elf_issue (const char *msg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (verbose >= 0)
Packit Service 97d2fb
    error (0, 0, "%s: %s: '%s'", msg, elf_errmsg (-1), current_path);
Packit Service 97d2fb
  issue_found = true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by parse_opt.  */
Packit Service 97d2fb
static bool flag_only_regular_files;
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
open_file (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (verbose > 1)
Packit Service 97d2fb
    fprintf (stderr, "debug: processing file: %s\n", current_path);
Packit Service 97d2fb
Packit Service 97d2fb
  file_fd = open (current_path, O_RDONLY | (flag_only_regular_files
Packit Service 97d2fb
					    ? O_NOFOLLOW : 0));
Packit Service 97d2fb
  if (file_fd < 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (!flag_only_regular_files || errno != ELOOP)
Packit Service 97d2fb
	issue (errno, N_("opening"));
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  struct stat st;
Packit Service 97d2fb
  if (fstat (file_fd, &st) != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      issue (errno, N_("reading"));
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Don't even bother with directories.  */
Packit Service 97d2fb
  if (S_ISDIR (st.st_mode)
Packit Service 97d2fb
      || (flag_only_regular_files && !S_ISREG (st.st_mode)))
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
close_file (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (file_fd >= 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      close (file_fd);
Packit Service 97d2fb
      file_fd = -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by open_elf.  */
Packit Service 97d2fb
static Elf *elf;
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by parse_opt.  */
Packit Service 97d2fb
static bool flag_compressed;
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
open_elf (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (!open_file ())
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Make sure the file descriptor is gone.  */
Packit Service 97d2fb
      close_file ();
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (flag_compressed)
Packit Service 97d2fb
    elf = dwelf_elf_begin (file_fd);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    elf = elf_begin (file_fd, ELF_C_READ, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_issue ("opening ELF file");
Packit Service 97d2fb
      close_file ();
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
close_elf (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_end (elf);
Packit Service 97d2fb
      elf = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  close_file ();
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
elf_kind_string (int kind)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (kind)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ELF_K_NONE:
Packit Service 97d2fb
      return "ELF_K_NONE";
Packit Service 97d2fb
    case ELF_K_AR:
Packit Service 97d2fb
      return "ELF_K_AR";
Packit Service 97d2fb
    case ELF_K_COFF:
Packit Service 97d2fb
      return "ELF_K_COFF"; /* libelf doesn't really support this.  */
Packit Service 97d2fb
    case ELF_K_ELF:
Packit Service 97d2fb
      return "ELF_K_ELF";
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return "<unknown>";
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
elf_type_string (int type)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (type)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ET_NONE:
Packit Service 97d2fb
      return "ET_NONE";
Packit Service 97d2fb
    case ET_REL:
Packit Service 97d2fb
      return "ET_REL";
Packit Service 97d2fb
    case ET_EXEC:
Packit Service 97d2fb
      return "ET_EXEC";
Packit Service 97d2fb
    case ET_DYN:
Packit Service 97d2fb
      return "ET_DYN";
Packit Service 97d2fb
    case ET_CORE:
Packit Service 97d2fb
      return "ET_CORE";
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return "<unknown>";
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int elf_type;
Packit Service 97d2fb
static bool has_program_load;
Packit Service 97d2fb
static bool has_sections;
Packit Service 97d2fb
static bool has_bits_alloc;
Packit Service 97d2fb
static bool has_program_interpreter;
Packit Service 97d2fb
static bool has_dynamic;
Packit Service 97d2fb
static bool has_soname;
Packit Service 97d2fb
static bool has_pie_flag;
Packit Service 97d2fb
static bool has_dt_debug;
Packit Service 97d2fb
static bool has_symtab;
Packit Service 97d2fb
static bool has_debug_sections;
Packit Service 97d2fb
static bool has_modinfo;
Packit Service 97d2fb
static bool has_gnu_linkonce_this_module;
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
run_classify (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Reset to unanalyzed default.  */
Packit Service 97d2fb
  elf_type = 0;
Packit Service 97d2fb
  has_program_load = false;
Packit Service 97d2fb
  has_sections = false;
Packit Service 97d2fb
  has_bits_alloc = false;
Packit Service 97d2fb
  has_program_interpreter = false;
Packit Service 97d2fb
  has_dynamic = false;
Packit Service 97d2fb
  has_soname = false;
Packit Service 97d2fb
  has_pie_flag = false;
Packit Service 97d2fb
  has_dt_debug = false;
Packit Service 97d2fb
  has_symtab = false;
Packit Service 97d2fb
  has_debug_sections = false;
Packit Service 97d2fb
  has_modinfo = false;
Packit Service 97d2fb
  has_gnu_linkonce_this_module = false;
Packit Service 97d2fb
Packit Service 97d2fb
  int kind = elf_kind (elf);
Packit Service 97d2fb
  if (verbose > 0)
Packit Service 97d2fb
    fprintf (stderr, "info: %s: ELF kind: %s (0x%x)\n", current_path,
Packit Service 97d2fb
	     elf_kind_string (kind), kind);
Packit Service 97d2fb
  if (kind != ELF_K_ELF)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  GElf_Ehdr ehdr_storage;
Packit Service 97d2fb
  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_storage);
Packit Service 97d2fb
  if (ehdr == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_issue (N_("ELF header"));
Packit Service 97d2fb
      return false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  elf_type = ehdr->e_type;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Examine program headers.  */
Packit Service 97d2fb
  GElf_Phdr dyn_seg = { .p_type = 0 };
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t nphdrs;
Packit Service 97d2fb
    if (elf_getphdrnum (elf, &nphdrs) != 0)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	elf_issue (N_("program headers"));
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
      }
Packit Service 97d2fb
    for (size_t phdr_idx = 0; phdr_idx < nphdrs; ++phdr_idx)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	GElf_Phdr phdr_storage;
Packit Service 97d2fb
	GElf_Phdr *phdr = gelf_getphdr (elf, phdr_idx, &phdr_storage);
Packit Service 97d2fb
	if (phdr == NULL)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    elf_issue (N_("program header"));
Packit Service 97d2fb
	    return false;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	if (phdr->p_type == PT_DYNAMIC)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    dyn_seg = *phdr;
Packit Service 97d2fb
	    has_dynamic = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	if (phdr->p_type == PT_INTERP)
Packit Service 97d2fb
	  has_program_interpreter = true;
Packit Service 97d2fb
	if (phdr->p_type == PT_LOAD)
Packit Service 97d2fb
	  has_program_load = true;
Packit Service 97d2fb
      }
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Do we have sections?  */
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t nshdrs;
Packit Service 97d2fb
    if (elf_getshdrnum (elf, &nshdrs) != 0)
Packit Service 97d2fb
      {
Packit Service 97d2fb
	elf_issue (N_("section headers"));
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
      }
Packit Service 97d2fb
    if (nshdrs > 0)
Packit Service 97d2fb
      has_sections = true;
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  {
Packit Service 97d2fb
    size_t shstrndx;
Packit Service 97d2fb
    if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
Packit Service 97d2fb
      {
Packit Service 97d2fb
	elf_issue (N_("section header string table index"));
Packit Service 97d2fb
	return false;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
    Elf_Scn *scn = NULL;
Packit Service 97d2fb
    while (true)
Packit Service 97d2fb
      {
Packit Service 97d2fb
        scn = elf_nextscn (elf, scn);
Packit Service 97d2fb
        if (scn == NULL)
Packit Service 97d2fb
          break;
Packit Service 97d2fb
        GElf_Shdr shdr_storage;
Packit Service 97d2fb
        GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_storage);
Packit Service 97d2fb
        if (shdr == NULL)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
            elf_issue (N_("could not obtain section header"));
Packit Service 97d2fb
	    return false;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
        const char *section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
Packit Service 97d2fb
        if (section_name == NULL)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
            elf_issue(N_("could not obtain section name"));
Packit Service 97d2fb
	    return false;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
        if (verbose > 2)
Packit Service 97d2fb
          fprintf (stderr, "debug: section header %s (type %d) found\n",
Packit Service 97d2fb
                   section_name, shdr->sh_type);
Packit Service 97d2fb
        if (shdr->sh_type == SHT_SYMTAB)
Packit Service 97d2fb
          {
Packit Service 97d2fb
            if (verbose > 1)
Packit Service 97d2fb
              fputs ("debug: symtab section found\n", stderr);
Packit Service 97d2fb
            has_symtab = true;
Packit Service 97d2fb
          }
Packit Service 97d2fb
	/* NOBITS and NOTE sections can be in any file.  We want to be
Packit Service 97d2fb
	   sure there is at least one other allocated section.  */
Packit Service 97d2fb
	if (shdr->sh_type != SHT_NOBITS
Packit Service 97d2fb
	    && shdr->sh_type != SHT_NOTE
Packit Service 97d2fb
	    && (shdr->sh_flags & SHF_ALLOC) != 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (verbose > 1 && !has_bits_alloc)
Packit Service 97d2fb
	      fputs ("debug: allocated (non-nobits/note) section found\n",
Packit Service 97d2fb
		     stderr);
Packit Service 97d2fb
	    has_bits_alloc = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
        const char *debug_prefix = ".debug_";
Packit Service 97d2fb
        const char *zdebug_prefix = ".zdebug_";
Packit Service 97d2fb
        if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0
Packit Service 97d2fb
	    || strncmp (section_name, zdebug_prefix,
Packit Service 97d2fb
			strlen (zdebug_prefix)) == 0)
Packit Service 97d2fb
          {
Packit Service 97d2fb
            if (verbose > 1 && !has_debug_sections)
Packit Service 97d2fb
              fputs ("debug: .debug_* section found\n", stderr);
Packit Service 97d2fb
            has_debug_sections = true;
Packit Service 97d2fb
          }
Packit Service 97d2fb
	if (strcmp (section_name, ".modinfo") == 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (verbose > 1)
Packit Service 97d2fb
	      fputs ("debug: .modinfo section found\n", stderr);
Packit Service 97d2fb
	    has_modinfo = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	if (strcmp (section_name, ".gnu.linkonce.this_module") == 0)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    if (verbose > 1)
Packit Service 97d2fb
	      fputs ("debug: .gnu.linkonce.this_module section found\n",
Packit Service 97d2fb
		     stderr);
Packit Service 97d2fb
	    has_gnu_linkonce_this_module = true;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
      }
Packit Service 97d2fb
  }
Packit Service 97d2fb
Packit Service 97d2fb
  /* Examine the dynamic section.  */
Packit Service 97d2fb
  if (has_dynamic)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset,
Packit Service 97d2fb
					     dyn_seg.p_filesz,
Packit Service 97d2fb
					     ELF_T_DYN);
Packit Service 97d2fb
      if (data != NULL)
Packit Service 97d2fb
	for (int dyn_idx = 0; ; ++dyn_idx)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    GElf_Dyn dyn_storage;
Packit Service 97d2fb
	    GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage);
Packit Service 97d2fb
	    if (dyn == NULL)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	    if (verbose > 2)
Packit Service 97d2fb
	      fprintf (stderr, "debug: dynamic entry %d"
Packit Service 97d2fb
		       " with tag %llu found\n",
Packit Service 97d2fb
		       dyn_idx, (unsigned long long int) dyn->d_tag);
Packit Service 97d2fb
	    if (dyn->d_tag == DT_SONAME)
Packit Service 97d2fb
	      has_soname = true;
Packit Service 97d2fb
	    if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE))
Packit Service 97d2fb
	      has_pie_flag = true;
Packit Service 97d2fb
	    if (dyn->d_tag == DT_DEBUG)
Packit Service 97d2fb
	      has_dt_debug = true;
Packit Service 97d2fb
	    if (dyn->d_tag == DT_NULL)
Packit Service 97d2fb
	      break;
Packit Service 97d2fb
	  }
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (verbose > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      fprintf (stderr, "info: %s: ELF type: %s (0x%x)\n", current_path,
Packit Service 97d2fb
	       elf_type_string (elf_type), elf_type);
Packit Service 97d2fb
      if (has_program_load)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: PT_LOAD found\n", current_path);
Packit Service 97d2fb
      if (has_sections)
Packit Service 97d2fb
	fprintf (stderr, "info: %s: has sections\n", current_path);
Packit Service 97d2fb
      if (has_bits_alloc)
Packit Service 97d2fb
	fprintf (stderr, "info: %s: allocated (real) section found\n",
Packit Service 97d2fb
		 current_path);
Packit Service 97d2fb
      if (has_program_interpreter)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: program interpreter found\n",
Packit Service 97d2fb
                 current_path);
Packit Service 97d2fb
      if (has_dynamic)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: dynamic segment found\n", current_path);
Packit Service 97d2fb
      if (has_soname)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: soname found\n", current_path);
Packit Service 97d2fb
      if (has_pie_flag)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: DF_1_PIE flag found\n", current_path);
Packit Service 97d2fb
      if (has_dt_debug)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: DT_DEBUG found\n", current_path);
Packit Service 97d2fb
      if (has_symtab)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: symbol table found\n", current_path);
Packit Service 97d2fb
      if (has_debug_sections)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: .debug_* section found\n", current_path);
Packit Service 97d2fb
      if (has_modinfo)
Packit Service 97d2fb
        fprintf (stderr, "info: %s: .modinfo section found\n", current_path);
Packit Service 97d2fb
      if (has_gnu_linkonce_this_module)
Packit Service 97d2fb
        fprintf (stderr,
Packit Service 97d2fb
		 "info: %s: .gnu.linkonce.this_module section found\n",
Packit Service 97d2fb
		 current_path);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_elf (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) != ELF_K_NONE;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_elf_file (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) == ELF_K_ELF;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_elf_archive (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) == ELF_K_AR;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_core (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) == ELF_K_ELF && elf_type == ET_CORE;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true if the file is a loadable object, which basically means
Packit Service 97d2fb
   it is an ELF file, but not a relocatable object or a core dump
Packit Service 97d2fb
   file.  (The kernel and various userspace components can load ET_REL
Packit Service 97d2fb
   files, but we disregard that for our classification purposes.)  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_loadable (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) == ELF_K_ELF
Packit Service 97d2fb
    && (elf_type == ET_EXEC || elf_type == ET_DYN)
Packit Service 97d2fb
    && has_program_load
Packit Service 97d2fb
    && (!has_sections || has_bits_alloc); /* It isn't debug-only.  */
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true if the file is an ELF file which has a symbol table or
Packit Service 97d2fb
   .debug_* sections (and thus can be stripped futher).  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_unstripped (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) != ELF_K_NONE
Packit Service 97d2fb
    && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
Packit Service 97d2fb
    && (has_symtab || has_debug_sections);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Return true if the file contains only debuginfo, but no loadable
Packit Service 97d2fb
   program bits.  Then it is most likely a separate .debug file, a dwz
Packit Service 97d2fb
   multi-file or a .dwo file.  Note that it can still be loadable,
Packit Service 97d2fb
   but in that case the phdrs shouldn't be trusted.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_debug_only (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return elf_kind (elf) != ELF_K_NONE
Packit Service 97d2fb
    && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN)
Packit Service 97d2fb
    && (has_debug_sections || has_symtab)
Packit Service 97d2fb
    && !has_bits_alloc;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_shared (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (!is_loadable ())
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* The ELF type is very clear: this is an executable.  */
Packit Service 97d2fb
  if (elf_type == ET_EXEC)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If there is no dynamic section, the file cannot be loaded as a
Packit Service 97d2fb
     shared object.  */
Packit Service 97d2fb
  if (!has_dynamic)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the object is marked as PIE, it is definitely an executable,
Packit Service 97d2fb
     and not a loadlable shared object.  */
Packit Service 97d2fb
  if (has_pie_flag)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Treat a DT_SONAME tag as a strong indicator that this is a shared
Packit Service 97d2fb
     object.  */
Packit Service 97d2fb
  if (has_soname)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This is probably a PIE program: there is no soname, but a program
Packit Service 97d2fb
     interpreter.  In theory, this file could be also a DSO with a
Packit Service 97d2fb
     soname implied by its file name that can be run as a program.
Packit Service 97d2fb
     This situation is impossible to resolve in the general case. */
Packit Service 97d2fb
  if (has_program_interpreter)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Roland McGrath mentions in
Packit Service 97d2fb
     <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
Packit Service 97d2fb
     that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
Packit Service 97d2fb
     matches current binutils behavior (version 2.32).  DT_DEBUG is
Packit Service 97d2fb
     added if bfd_link_executable returns true or if bfd_link_pic
Packit Service 97d2fb
     returns false, depending on the architectures.  However, DT_DEBUG
Packit Service 97d2fb
     is not documented as being specific to executables, therefore use
Packit Service 97d2fb
     it only as a low-priority discriminator.  */
Packit Service 97d2fb
  if (has_dt_debug)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_executable (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (!is_loadable ())
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* A loadable object which is not a shared object is treated as an
Packit Service 97d2fb
     executable.  */
Packit Service 97d2fb
  return !is_shared ();
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Like is_executable, but the object can also be a shared library at
Packit Service 97d2fb
   the same time.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_program (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (!is_loadable ())
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* The ELF type is very clear: this is an executable.  */
Packit Service 97d2fb
  if (elf_type == ET_EXEC)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the object is marked as PIE, it is definitely an executable,
Packit Service 97d2fb
     and not a loadlable shared object.  */
Packit Service 97d2fb
  if (has_pie_flag)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This is probably a PIE program. It isn't ET_EXEC, but has a
Packit Service 97d2fb
     program interpreter. In theory, this file could be also a DSO
Packit Service 97d2fb
     with a soname. This situation is impossible to resolve in the
Packit Service 97d2fb
     general case. See is_shared. This is different from
Packit Service 97d2fb
     is_executable.  */
Packit Service 97d2fb
  if (has_program_interpreter)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Roland McGrath mentions in
Packit Service 97d2fb
     <https://www.sourceware.org/ml/libc-alpha/2015-03/msg00605.html>,
Packit Service 97d2fb
     that “we defined a PIE as an ET_DYN with a DT_DEBUG”.  This
Packit Service 97d2fb
     matches current binutils behavior (version 2.32).  DT_DEBUG is
Packit Service 97d2fb
     added if bfd_link_executable returns true or if bfd_link_pic
Packit Service 97d2fb
     returns false, depending on the architectures.  However, DT_DEBUG
Packit Service 97d2fb
     is not documented as being specific to executables, therefore use
Packit Service 97d2fb
     it only as a low-priority discriminator.  */
Packit Service 97d2fb
  if (has_dt_debug)
Packit Service 97d2fb
    return true;
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Like is_shared but the library could also be an executable.  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_library  (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Only ET_DYN can be shared libraries.  */
Packit Service 97d2fb
  if (elf_type != ET_DYN)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  if (!is_loadable ())
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* Without a PT_DYNAMIC segment the library cannot be loaded.  */
Packit Service 97d2fb
  if (!has_dynamic)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This really is a (PIE) executable.  See is_shared.  */
Packit Service 97d2fb
  if (has_pie_flag || has_dt_debug)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  /* It could still (also) be a (PIE) executable, but most likely you
Packit Service 97d2fb
     can dlopen it just fine.  */
Packit Service 97d2fb
  return true;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Returns true if the file is a linux kernel module (is ET_REL and
Packit Service 97d2fb
   has the two magic sections .modinfo and .gnu.linkonce.this_module).  */
Packit Service 97d2fb
static bool
Packit Service 97d2fb
is_linux_kernel_module (void)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return (elf_kind (elf) == ELF_K_ELF
Packit Service 97d2fb
	  && elf_type == ET_REL
Packit Service 97d2fb
	  && has_modinfo
Packit Service 97d2fb
	  && has_gnu_linkonce_this_module);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
enum classify_requirement { do_not_care, required, forbidden };
Packit Service 97d2fb
Packit Service 97d2fb
enum classify_check
Packit Service 97d2fb
{
Packit Service 97d2fb
  classify_elf,
Packit Service 97d2fb
  classify_elf_file,
Packit Service 97d2fb
  classify_elf_archive,
Packit Service 97d2fb
  classify_core,
Packit Service 97d2fb
  classify_unstripped,
Packit Service 97d2fb
  classify_executable,
Packit Service 97d2fb
  classify_program,
Packit Service 97d2fb
  classify_shared,
Packit Service 97d2fb
  classify_library,
Packit Service 97d2fb
  classify_linux_kernel_module,
Packit Service 97d2fb
  classify_debug_only,
Packit Service 97d2fb
  classify_loadable,
Packit Service 97d2fb
Packit Service 97d2fb
  classify_check_last = classify_loadable
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
enum
Packit Service 97d2fb
{
Packit Service 97d2fb
  classify_check_offset = 1000,
Packit Service 97d2fb
  classify_check_not_offset = 2000,
Packit Service 97d2fb
Packit Service 97d2fb
  classify_flag_stdin = 3000,
Packit Service 97d2fb
  classify_flag_stdin0,
Packit Service 97d2fb
  classify_flag_no_stdin,
Packit Service 97d2fb
  classify_flag_print,
Packit Service 97d2fb
  classify_flag_print0,
Packit Service 97d2fb
  classify_flag_no_print,
Packit Service 97d2fb
  classify_flag_matching,
Packit Service 97d2fb
  classify_flag_not_matching,
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
classify_check_positive (int key)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return key >= classify_check_offset
Packit Service 97d2fb
    && key <= classify_check_offset + classify_check_last;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
classify_check_negative (int key)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return key >= classify_check_not_offset
Packit Service 97d2fb
    && key <= classify_check_not_offset + classify_check_last;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Set by parse_opt.  */
Packit Service 97d2fb
static enum classify_requirement requirements[classify_check_last + 1];
Packit Service 97d2fb
static enum { no_stdin, do_stdin, do_stdin0 } flag_stdin;
Packit Service 97d2fb
static enum { no_print, do_print, do_print0 } flag_print;
Packit Service 97d2fb
static bool flag_print_matching = true;
Packit Service 97d2fb
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg __attribute__ ((unused)),
Packit Service 97d2fb
           struct argp_state *state __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (classify_check_positive (key))
Packit Service 97d2fb
    requirements[key - classify_check_offset] = required;
Packit Service 97d2fb
  else if (classify_check_negative (key))
Packit Service 97d2fb
    requirements[key - classify_check_not_offset] = forbidden;
Packit Service 97d2fb
  else
Packit Service 97d2fb
    switch (key)
Packit Service 97d2fb
      {
Packit Service 97d2fb
      case 'v':
Packit Service 97d2fb
        ++verbose;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case 'q':
Packit Service 97d2fb
	--verbose;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case 'z':
Packit Service 97d2fb
	flag_compressed = true;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case 'f':
Packit Service 97d2fb
	flag_only_regular_files = true;
Packit Service 97d2fb
	break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_stdin:
Packit Service 97d2fb
        flag_stdin = do_stdin;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_stdin0:
Packit Service 97d2fb
        flag_stdin = do_stdin0;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_no_stdin:
Packit Service 97d2fb
        flag_stdin = no_stdin;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_print:
Packit Service 97d2fb
        flag_print = do_print;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_print0:
Packit Service 97d2fb
        flag_print = do_print0;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_no_print:
Packit Service 97d2fb
        flag_print = no_print;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_matching:
Packit Service 97d2fb
        flag_print_matching = true;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      case classify_flag_not_matching:
Packit Service 97d2fb
        flag_print_matching = false;
Packit Service 97d2fb
        break;
Packit Service 97d2fb
Packit Service 97d2fb
      default:
Packit Service 97d2fb
        return ARGP_ERR_UNKNOWN;
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Perform requested checks against the file at current_path.  If
Packit Service 97d2fb
   necessary, sets *STATUS to 1 if checks failed.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
process_current_path (int *status)
Packit Service 97d2fb
{
Packit Service 97d2fb
  bool checks_passed = true;
Packit Service 97d2fb
Packit Service 97d2fb
  if (open_elf () && run_classify ())
Packit Service 97d2fb
    {
Packit Service 97d2fb
      bool checks[] =
Packit Service 97d2fb
        {
Packit Service 97d2fb
	 [classify_elf] = is_elf (),
Packit Service 97d2fb
	 [classify_elf_file] = is_elf_file (),
Packit Service 97d2fb
	 [classify_elf_archive] = is_elf_archive (),
Packit Service 97d2fb
	 [classify_core] = is_core (),
Packit Service 97d2fb
	 [classify_unstripped] = is_unstripped (),
Packit Service 97d2fb
	 [classify_executable] = is_executable (),
Packit Service 97d2fb
	 [classify_program] = is_program (),
Packit Service 97d2fb
	 [classify_shared] = is_shared (),
Packit Service 97d2fb
	 [classify_library] = is_library (),
Packit Service 97d2fb
	 [classify_linux_kernel_module] = is_linux_kernel_module (),
Packit Service 97d2fb
	 [classify_debug_only] = is_debug_only (),
Packit Service 97d2fb
	 [classify_loadable] = is_loadable (),
Packit Service 97d2fb
	};
Packit Service 97d2fb
Packit Service 97d2fb
      if (verbose > 1)
Packit Service 97d2fb
        {
Packit Service 97d2fb
	  if (checks[classify_elf])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: elf\n", current_path);
Packit Service 97d2fb
	  if (checks[classify_elf_file])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: elf_file\n", current_path);
Packit Service 97d2fb
	  if (checks[classify_elf_archive])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: elf_archive\n", current_path);
Packit Service 97d2fb
	  if (checks[classify_core])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: core\n", current_path);
Packit Service 97d2fb
          if (checks[classify_unstripped])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: unstripped\n", current_path);
Packit Service 97d2fb
          if (checks[classify_executable])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: executable\n", current_path);
Packit Service 97d2fb
          if (checks[classify_program])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: program\n", current_path);
Packit Service 97d2fb
          if (checks[classify_shared])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: shared\n", current_path);
Packit Service 97d2fb
          if (checks[classify_library])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: library\n", current_path);
Packit Service 97d2fb
	  if (checks[classify_linux_kernel_module])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: linux kernel module\n", current_path);
Packit Service 97d2fb
	  if (checks[classify_debug_only])
Packit Service 97d2fb
	    fprintf (stderr, "debug: %s: debug-only\n", current_path);
Packit Service 97d2fb
          if (checks[classify_loadable])
Packit Service 97d2fb
            fprintf (stderr, "debug: %s: loadable\n", current_path);
Packit Service 97d2fb
        }
Packit Service 97d2fb
Packit Service 97d2fb
      for (enum classify_check check = 0;
Packit Service 97d2fb
           check <= classify_check_last; ++check)
Packit Service 97d2fb
        switch (requirements[check])
Packit Service 97d2fb
          {
Packit Service 97d2fb
          case required:
Packit Service 97d2fb
            if (!checks[check])
Packit Service 97d2fb
              checks_passed = false;
Packit Service 97d2fb
            break;
Packit Service 97d2fb
          case forbidden:
Packit Service 97d2fb
            if (checks[check])
Packit Service 97d2fb
              checks_passed = false;
Packit Service 97d2fb
            break;
Packit Service 97d2fb
          case do_not_care:
Packit Service 97d2fb
            break;
Packit Service 97d2fb
          }
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (file_fd == -1)
Packit Service 97d2fb
    checks_passed = false; /* There is nothing to check, bad file.  */
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      for (enum classify_check check = 0;
Packit Service 97d2fb
           check <= classify_check_last; ++check)
Packit Service 97d2fb
        if (requirements[check] == required)
Packit Service 97d2fb
          checks_passed = false;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  close_elf ();
Packit Service 97d2fb
Packit Service 97d2fb
  switch (flag_print)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case do_print:
Packit Service 97d2fb
      if (checks_passed == flag_print_matching)
Packit Service 97d2fb
        puts (current_path);
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case do_print0:
Packit Service 97d2fb
      if (checks_passed == flag_print_matching)
Packit Service 97d2fb
        if (fwrite (current_path, strlen (current_path) + 1, 1, stdout) < 1)
Packit Service 97d2fb
	  issue (errno, N_("writing to standard output"));
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case no_print:
Packit Service 97d2fb
      if (!checks_passed)
Packit Service 97d2fb
        *status = 1;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Called to process standard input if flag_stdin is not no_stdin.  */
Packit Service 97d2fb
static void
Packit Service 97d2fb
process_stdin (int *status)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char delim;
Packit Service 97d2fb
  if (flag_stdin == do_stdin0)
Packit Service 97d2fb
    delim = '\0';
Packit Service 97d2fb
  else
Packit Service 97d2fb
    delim = '\n';
Packit Service 97d2fb
Packit Service 97d2fb
  char *buffer = NULL;
Packit Service 97d2fb
  size_t buffer_size = 0;
Packit Service 97d2fb
  while (true)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      ssize_t ret = getdelim (&buffer, &buffer_size, delim, stdin);
Packit Service 97d2fb
      if (ferror (stdin))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  current_path = NULL;
Packit Service 97d2fb
	  issue (errno, N_("reading from standard input"));
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (feof (stdin))
Packit Service 97d2fb
        break;
Packit Service 97d2fb
      if (ret < 0)
Packit Service 97d2fb
        abort ();           /* Cannot happen due to error checks above.  */
Packit Service 97d2fb
      if (delim != '\0' && ret > 0 && buffer[ret - 1] == '\n')
Packit Service 97d2fb
        buffer[ret - 1] = '\0';
Packit Service 97d2fb
      current_path = buffer;
Packit Service 97d2fb
      process_current_path (status);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  free (buffer);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char **argv)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const struct argp_option options[] =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      { NULL, 0, NULL, OPTION_DOC, N_("Classification options"), 1 },
Packit Service 97d2fb
      { "elf", classify_check_offset + classify_elf, NULL, 0,
Packit Service 97d2fb
        N_("File looks like an ELF object or archive/static library (default)")
Packit Service 97d2fb
	, 1 },
Packit Service 97d2fb
      { "elf-file", classify_check_offset + classify_elf_file, NULL, 0,
Packit Service 97d2fb
        N_("File is an regular ELF object (not an archive/static library)")
Packit Service 97d2fb
	, 1 },
Packit Service 97d2fb
      { "elf-archive", classify_check_offset + classify_elf_archive, NULL, 0,
Packit Service 97d2fb
        N_("File is an ELF archive or static library")
Packit Service 97d2fb
	, 1 },
Packit Service 97d2fb
      { "core", classify_check_offset + classify_core, NULL, 0,
Packit Service 97d2fb
        N_("File is an ELF core dump file")
Packit Service 97d2fb
	, 1 },
Packit Service 97d2fb
      { "unstripped", classify_check_offset + classify_unstripped, NULL, 0,
Packit Service 97d2fb
        N_("File is an ELF file with symbol table or .debug_* sections \
Packit Service 97d2fb
and can be stripped further"), 1 },
Packit Service 97d2fb
      { "executable", classify_check_offset + classify_executable, NULL, 0,
Packit Service 97d2fb
        N_("File is (primarily) an ELF program executable \
Packit Service 97d2fb
(not primarily a DSO)"), 1 },
Packit Service 97d2fb
      { "program", classify_check_offset + classify_program, NULL, 0,
Packit Service 97d2fb
        N_("File is an ELF program executable \
Packit Service 97d2fb
(might also be a DSO)"), 1 },
Packit Service 97d2fb
      { "shared", classify_check_offset + classify_shared, NULL, 0,
Packit Service 97d2fb
        N_("File is (primarily) an ELF shared object (DSO) \
Packit Service 97d2fb
(not primarily an executable)"), 1 },
Packit Service 97d2fb
      { "library", classify_check_offset + classify_library, NULL, 0,
Packit Service 97d2fb
        N_("File is an ELF shared object (DSO) \
Packit Service 97d2fb
(might also be an executable)"), 1 },
Packit Service 97d2fb
      { "linux-kernel-module", (classify_check_offset
Packit Service 97d2fb
				+ classify_linux_kernel_module), NULL, 0,
Packit Service 97d2fb
        N_("File is a linux kernel module"), 1 },
Packit Service 97d2fb
      { "debug-only", (classify_check_offset + classify_debug_only), NULL, 0,
Packit Service 97d2fb
        N_("File is a debug only ELF file \
Packit Service 97d2fb
(separate .debug, .dwo or dwz multi-file)"), 1 },
Packit Service 97d2fb
      { "loadable", classify_check_offset + classify_loadable, NULL, 0,
Packit Service 97d2fb
        N_("File is a loadable ELF object (program or shared object)"), 1 },
Packit Service 97d2fb
Packit Service 97d2fb
      /* Negated versions of the above.  */
Packit Service 97d2fb
      { "not-elf", classify_check_not_offset + classify_elf,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-elf-file", classify_check_not_offset + classify_elf_file,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-elf-archive", classify_check_not_offset + classify_elf_archive,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-core", classify_check_not_offset + classify_core,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-unstripped", classify_check_not_offset + classify_unstripped,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-executable", classify_check_not_offset + classify_executable,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-program", classify_check_not_offset + classify_program,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-shared", classify_check_not_offset + classify_shared,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-library", classify_check_not_offset + classify_library,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-linux-kernel-module", (classify_check_not_offset
Packit Service 97d2fb
				    + classify_linux_kernel_module),
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-debug-only", (classify_check_not_offset + classify_debug_only),
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
      { "not-loadable", classify_check_not_offset + classify_loadable,
Packit Service 97d2fb
        NULL, OPTION_HIDDEN, NULL, 1 },
Packit Service 97d2fb
Packit Service 97d2fb
      { NULL, 0, NULL, OPTION_DOC, N_("Input flags"), 2 },
Packit Service 97d2fb
      { "file", 'f', NULL, 0,
Packit Service 97d2fb
        N_("Only classify regular (not symlink nor special device) files"), 2 },
Packit Service 97d2fb
      { "stdin", classify_flag_stdin, NULL, 0,
Packit Service 97d2fb
        N_("Also read file names to process from standard input, \
Packit Service 97d2fb
separated by newlines"), 2 },
Packit Service 97d2fb
      { "stdin0", classify_flag_stdin0, NULL, 0,
Packit Service 97d2fb
        N_("Also read file names to process from standard input, \
Packit Service 97d2fb
separated by ASCII NUL bytes"), 2 },
Packit Service 97d2fb
      { "no-stdin", classify_flag_stdin, NULL, 0,
Packit Service 97d2fb
        N_("Do not read files from standard input (default)"), 2 },
Packit Service 97d2fb
      { "compressed", 'z', NULL, 0,
Packit Service 97d2fb
	N_("Try to open compressed files or embedded (kernel) ELF images"),
Packit Service 97d2fb
	2 },
Packit Service 97d2fb
Packit Service 97d2fb
      { NULL, 0, NULL, OPTION_DOC, N_("Output flags"), 3 },
Packit Service 97d2fb
      { "print", classify_flag_print, NULL, 0,
Packit Service 97d2fb
        N_("Output names of files, separated by newline"), 3 },
Packit Service 97d2fb
      { "print0", classify_flag_print0, NULL, 0,
Packit Service 97d2fb
        N_("Output names of files, separated by ASCII NUL"), 3 },
Packit Service 97d2fb
      { "no-print", classify_flag_no_print, NULL, 0,
Packit Service 97d2fb
        N_("Do not output file names"), 3 },
Packit Service 97d2fb
      { "matching", classify_flag_matching, NULL, 0,
Packit Service 97d2fb
        N_("If printing file names, print matching files (default)"), 3 },
Packit Service 97d2fb
      { "not-matching", classify_flag_not_matching, NULL, 0,
Packit Service 97d2fb
        N_("If printing file names, print files that do not match"), 3 },
Packit Service 97d2fb
Packit Service 97d2fb
      { NULL, 0, NULL, OPTION_DOC, N_("Additional flags"), 4 },
Packit Service 97d2fb
      { "verbose", 'v', NULL, 0,
Packit Service 97d2fb
        N_("Output additional information (can be specified multiple times)"), 4 },
Packit Service 97d2fb
      { "quiet", 'q', NULL, 0,
Packit Service 97d2fb
        N_("Suppress some error output (counterpart to --verbose)"), 4 },
Packit Service 97d2fb
      { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  const struct argp argp =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .options = options,
Packit Service 97d2fb
      .parser = parse_opt,
Packit Service 97d2fb
      .args_doc = N_("FILE..."),
Packit Service 97d2fb
      .doc = N_("\
Packit Service 97d2fb
Determine the type of an ELF file.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
All of the classification options must apply at the same time to a \
Packit Service 97d2fb
particular file.  Classification options can be negated using a \
Packit Service 97d2fb
\"--not-\" prefix.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
Since modern ELF does not clearly distinguish between programs and \
Packit Service 97d2fb
dynamic shared objects, you should normally use either --executable or \
Packit Service 97d2fb
--shared to identify the primary purpose of a file.  \
Packit Service 97d2fb
Only one of the --shared and --executable checks can pass for a file.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
If you want to know whether an ELF object might a program or a \
Packit Service 97d2fb
shared library (but could be both), then use --program or --library. \
Packit Service 97d2fb
Some ELF files will classify as both a program and a library.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
If you just want to know whether an ELF file is loadable (as program \
Packit Service 97d2fb
or library) use --loadable.  Note that files that only contain \
Packit Service 97d2fb
(separate) debug information (--debug-only) are never --loadable (even \
Packit Service 97d2fb
though they might contain program headers).  Linux kernel modules are \
Packit Service 97d2fb
also not --loadable (in the normal sense).\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
Without any of the --print options, the program exits with status 0 \
Packit Service 97d2fb
if the requested checks pass for all input files, with 1 if a check \
Packit Service 97d2fb
fails for any file, and 2 if there is an environmental issue (such \
Packit Service 97d2fb
as a file read error or a memory allocation error).\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
When printing file names, the program exits with status 0 even if \
Packit Service 97d2fb
no file names are printed, and exits with status 2 if there is an \
Packit Service 97d2fb
environmental issue.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
On usage error (e.g. a bad option was given), the program exits with \
Packit Service 97d2fb
a status code larger than 2.\
Packit Service 97d2fb
\n\n\
Packit Service 97d2fb
The --quiet or -q option suppresses some error warning output, but \
Packit Service 97d2fb
doesn't change the exit status.\
Packit Service 97d2fb
")
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  /* Require that the file is an ELF file by default.  User can
Packit Service 97d2fb
     disable with --not-elf.  */
Packit Service 97d2fb
  requirements[classify_elf] = required;
Packit Service 97d2fb
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
Packit Service 97d2fb
    return 2;
Packit Service 97d2fb
Packit Service 97d2fb
  elf_version (EV_CURRENT);
Packit Service 97d2fb
Packit Service 97d2fb
  int status = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  for (int i = remaining; i < argc; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      current_path = argv[i];
Packit Service 97d2fb
      process_current_path (&status);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (flag_stdin != no_stdin)
Packit Service 97d2fb
    process_stdin (&status);
Packit Service 97d2fb
Packit Service 97d2fb
  if (issue_found)
Packit Service 97d2fb
    return 2;
Packit Service 97d2fb
Packit Service 97d2fb
  return status;
Packit Service 97d2fb
}