From b389a9343193adb357500ccf018ff56495641697 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sat, 20 Jul 2019 23:30:35 +0200 Subject: [PATCH] elfclassify: Add elfclassify tests and fix issues found. --- src/elfclassify.c | 113 +++++++----- tests/Makefile.am | 7 +- tests/run-elfclassify-self.sh | 36 ++++ tests/run-elfclassify.sh | 327 ++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 51 deletions(-) create mode 100755 tests/run-elfclassify-self.sh create mode 100755 tests/run-elfclassify.sh diff --git a/src/elfclassify.c b/src/elfclassify.c index 83a97d47c..1df0789d2 100644 --- a/src/elfclassify.c +++ b/src/elfclassify.c @@ -202,7 +202,8 @@ elf_type_string (int type) static int elf_type; static bool has_program_load; -static bool has_progbits_alloc; +static bool has_sections; +static bool has_bits_alloc; static bool has_program_interpreter; static bool has_dynamic; static bool has_soname; @@ -219,7 +220,8 @@ run_classify (void) /* Reset to unanalyzed default. */ elf_type = 0; has_program_load = false; - has_progbits_alloc = false; + has_sections = false; + has_bits_alloc = false; has_program_interpreter = false; has_dynamic = false; has_soname = false; @@ -247,6 +249,7 @@ run_classify (void) elf_type = ehdr->e_type; /* Examine program headers. */ + GElf_Phdr dyn_seg = {}; { size_t nphdrs; if (elf_getphdrnum (elf, &nphdrs) != 0) @@ -264,7 +267,10 @@ run_classify (void) return false; } if (phdr->p_type == PT_DYNAMIC) - has_dynamic = true; + { + dyn_seg = *phdr; + has_dynamic = true; + } if (phdr->p_type == PT_INTERP) has_program_interpreter = true; if (phdr->p_type == PT_LOAD) @@ -272,7 +278,18 @@ run_classify (void) } } - Elf_Scn *dyn_section = NULL; + /* Do we have sections? */ + { + size_t nshdrs; + if (elf_getshdrnum (elf, &nshdrs) != 0) + { + elf_issue (N_("section headers")); + return false; + } + if (nshdrs > 0) + has_sections = true; + } + { size_t shstrndx; if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0)) @@ -303,26 +320,28 @@ run_classify (void) if (verbose > 2) fprintf (stderr, "debug: section header %s (type %d) found\n", section_name, shdr->sh_type); - if (shdr->sh_type == SHT_DYNAMIC) - { - if (verbose > 1) - fputs ("debug: dynamic section found\n", stderr); - dyn_section = scn; - } if (shdr->sh_type == SHT_SYMTAB) { if (verbose > 1) fputs ("debug: symtab section found\n", stderr); has_symtab = true; } - if (shdr->sh_type == SHT_PROGBITS && (shdr->sh_flags & SHF_ALLOC) != 0) + /* NOBITS and NOTE sections can be in any file. We want to be + sure there is at least one other allocated section. */ + if (shdr->sh_type != SHT_NOBITS + && shdr->sh_type != SHT_NOTE + && (shdr->sh_flags & SHF_ALLOC) != 0) { - if (verbose > 1 && !has_progbits_alloc) - fputs ("debug: allocated PROGBITS section found\n", stderr); - has_progbits_alloc = true; + if (verbose > 1 && !has_bits_alloc) + fputs ("debug: allocated (non-nobits/note) section found\n", + stderr); + has_bits_alloc = true; } const char *debug_prefix = ".debug_"; - if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0) + const char *zdebug_prefix = ".zdebug_"; + if (strncmp (section_name, debug_prefix, strlen (debug_prefix)) == 0 + || strncmp (section_name, zdebug_prefix, + strlen (zdebug_prefix)) == 0) { if (verbose > 1 && !has_debug_sections) fputs ("debug: .debug_* section found\n", stderr); @@ -347,34 +366,29 @@ run_classify (void) /* Examine the dynamic section. */ if (has_dynamic) { - if (dyn_section != NULL) - { - Elf_Data *data = elf_getdata (dyn_section, NULL); - if (verbose > 2) - fprintf (stderr, "debug: Elf_Data for dynamic section: %p\n", - data); - - if (data != NULL) - for (int dyn_idx = 0; ; ++dyn_idx) - { - GElf_Dyn dyn_storage; - GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage); - if (dyn == NULL) - break; - if (verbose > 2) - fprintf (stderr, "debug: dynamic entry %d" - " with tag %llu found\n", - dyn_idx, (unsigned long long int) dyn->d_tag); - if (dyn->d_tag == DT_SONAME) - has_soname = true; - if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE)) - has_pie_flag = true; - if (dyn->d_tag == DT_DEBUG) - has_dt_debug = true; - if (dyn->d_tag == DT_NULL) - break; - } - } + Elf_Data *data = elf_getdata_rawchunk (elf, dyn_seg.p_offset, + dyn_seg.p_filesz, + ELF_T_DYN); + if (data != NULL) + for (int dyn_idx = 0; ; ++dyn_idx) + { + GElf_Dyn dyn_storage; + GElf_Dyn *dyn = gelf_getdyn (data, dyn_idx, &dyn_storage); + if (dyn == NULL) + break; + if (verbose > 2) + fprintf (stderr, "debug: dynamic entry %d" + " with tag %llu found\n", + dyn_idx, (unsigned long long int) dyn->d_tag); + if (dyn->d_tag == DT_SONAME) + has_soname = true; + if (dyn->d_tag == DT_FLAGS_1 && (dyn->d_un.d_val & DF_1_PIE)) + has_pie_flag = true; + if (dyn->d_tag == DT_DEBUG) + has_dt_debug = true; + if (dyn->d_tag == DT_NULL) + break; + } } if (verbose > 0) @@ -383,8 +397,10 @@ run_classify (void) elf_type_string (elf_type), elf_type); if (has_program_load) fprintf (stderr, "info: %s: PT_LOAD found\n", current_path); - if (has_progbits_alloc) - fprintf (stderr, "info: %s: allocated PROGBITS section found\n", + if (has_sections) + fprintf (stderr, "info: %s: has sections\n", current_path); + if (has_bits_alloc) + fprintf (stderr, "info: %s: allocated (real) section found\n", current_path); if (has_program_interpreter) fprintf (stderr, "info: %s: program interpreter found\n", @@ -445,7 +461,8 @@ is_loadable (void) { return elf_kind (elf) == ELF_K_ELF && (elf_type == ET_EXEC || elf_type == ET_DYN) - && has_program_load; + && has_program_load + && (!has_sections || has_bits_alloc); /* It isn't debug-only. */ } /* Return true if the file is an ELF file which has a symbol table or @@ -467,8 +484,8 @@ is_debug_only (void) { return elf_kind (elf) != ELF_K_NONE && (elf_type == ET_REL || elf_type == ET_EXEC || elf_type == ET_DYN) - && has_debug_sections - && !has_progbits_alloc; + && (has_debug_sections || has_symtab) + && !has_bits_alloc; } static bool diff --git a/tests/Makefile.am b/tests/Makefile.am index 0ac353152..2ff7dfc46 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -164,7 +164,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-typeiter-many.sh run-strip-test-many.sh \ run-strip-version.sh run-xlate-note.sh \ run-readelf-discr.sh \ - run-dwelf_elf_e_machine_string.sh + run-dwelf_elf_e_machine_string.sh \ + run-elfclassify.sh run-elfclassify-self.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -435,8 +436,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-xlate-note.sh \ run-readelf-discr.sh \ testfile-rng.debug.bz2 testfile-urng.debug.bz2 \ - run-dwelf_elf_e_machine_string.sh - + run-dwelf_elf_e_machine_string.sh \ + run-elfclassify.sh run-elfclassify-self.sh if USE_VALGRIND valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1' diff --git a/tests/run-elfclassify-self.sh b/tests/run-elfclassify-self.sh new file mode 100755 index 000000000..c48ab9c93 --- /dev/null +++ b/tests/run-elfclassify-self.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Copyright (C) 2019 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +testrun_on_self ${abs_top_builddir}/src/elfclassify --elf-file +testrun_on_self ${abs_top_builddir}/src/elfclassify --not-core +testrun_on_self ${abs_top_builddir}/src/elfclassify --unstripped +testrun_on_self ${abs_top_builddir}/src/elfclassify --not-linux-kernel-module + +testrun_on_self_lib ${abs_top_builddir}/src/elfclassify --shared +testrun_on_self_lib ${abs_top_builddir}/src/elfclassify --loadable +testrun_on_self_lib ${abs_top_builddir}/src/elfclassify --not-executable +testrun_on_self_lib ${abs_top_builddir}/src/elfclassify --not-program + +testrun_on_self_exe ${abs_top_builddir}/src/elfclassify --executable +testrun_on_self_exe ${abs_top_builddir}/src/elfclassify --program +testrun_on_self_exe ${abs_top_builddir}/src/elfclassify --loadable +testrun_on_self_exe ${abs_top_builddir}/src/elfclassify --not-shared + +testrun ${abs_top_builddir}/src/elfclassify --not-shared $self_test_files_obj +testrun ${abs_top_builddir}/src/elfclassify --not-executable $self_test_files_obj diff --git a/tests/run-elfclassify.sh b/tests/run-elfclassify.sh new file mode 100755 index 000000000..5a849bbdd --- /dev/null +++ b/tests/run-elfclassify.sh @@ -0,0 +1,327 @@ +#!/bin/sh +# Copyright (C) 2019 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +core_files=\ +"testfile_aarch64_core \ + testfile-backtrace-demangle.core \ + testfiledwarfinlines.core \ + testfile_i686_core \ + testfile-m68k-core \ + testfile-riscv64-core \ + backtrace.aarch64.core \ + backtrace.i386.core \ + backtrace.ppc.core \ + backtrace.s390.core" + +testfiles $core_files + +echo "elfclassify --core" +testrun ${abs_top_builddir}/src/elfclassify --core $core_files +testrun_compare ${abs_top_builddir}/src/elfclassify --core --print $core_files <