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