From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 55249 invoked by alias); 20 Jul 2019 21:40:54 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 55238 invoked by uid 89); 20 Jul 2019 21:40:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.100.3 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,SPF_PASS autolearn=ham version=3.3.1 spammy=U*mark, 2201, fprintf X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,SPF_PASS autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 20 Jul 2019 21:40:49 +0000 Received: from librem.wildebeest.org (dhcp-089-098-233-039.chello.nl [89.98.233.39]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 2682F30012F3; Sat, 20 Jul 2019 23:40:45 +0200 (CEST) Received: by librem.wildebeest.org (Postfix, from userid 1000) id 250AAC013E; Sat, 20 Jul 2019 23:40:45 +0200 (CEST) Date: Sat, 20 Jul 2019 21:40:00 -0000 From: Mark Wielaard To: Florian Weimer Cc: elfutils-devel@sourceware.org, Panu Matilainen Subject: Re: [PATCH] elfclassify tool Message-ID: <20190720214045.GB2851@wildebeest.org> References: <87k1fz8c9q.fsf@oldenburg2.str.redhat.com> <2e6a27c552ae5e365db54ca6b432c77c9ad5b041.camel@klomp.org> <871s22yybt.fsf@oldenburg2.str.redhat.com> <8736mfzhob.fsf@oldenburg2.str.redhat.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="FCuugMFkClbJLl1L" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.10.1 (2018-07-13) X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2019-q3/txt/msg00071.txt.bz2 --FCuugMFkClbJLl1L Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 884 On Fri, Jul 19, 2019 at 02:47:09PM +0200, Mark Wielaard wrote: > The individual commits can be found here: > https://code.wildebeest.org/git/user/mjw/elfutils/log/?h=elfclassify > > Please let me know if any of this looks bad or unusual. > > I'll write some testcases. And as always when writing tests you find some corner cases :) So the attached is some testcases plus some fixes: - Handle files without sections (only phdrs), in particular handle PT_DYNAMIC directly (not through a section). - is_loadable should check whether it isn't a debug-only file (but only if there are section headers, if not, it cannot be debug-only). - For .debug_only we can also have just a .symtab (but no .debug sections). And any allocated section makes it not-debug-only (except for SHT_NOBITS or SHT_NOTE) - Detect .zdebug sections too (old GNU compressed ELF sections). Cheers, Mark --FCuugMFkClbJLl1L Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0001-elfclassify-Add-elfclassify-tests-and-fix-issues-fou.patch" Content-length: 22130 >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 <