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