summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2025-02-18 23:24:48 +0100
committerMark Wielaard <[email protected]>2025-03-01 16:20:33 +0100
commitc65c467e83431ec5189f65fe11ad9a01d82af217 (patch)
tree1bd023235b7856d86edec84b567bad86cc3c3a81 /tests
parentdfa7b2c23ddabcba2a4972fa67d3c670ae31f1ee (diff)
libelf: Rewrite elf_scnshndx, extended index table handling
elf_scnshndx is a elfutils extension to libelf that given a SHT_SYMTAB section returns the index to the corresponding SHT_SYMTAB_SHNDX section, if it exists. This is needed when there are more than 64K sections and there are symbols that have to refer to a section with an index larger than 64K, because the Elf Sym st_shndx field is only 16 bits. This was implemented by adding an shndx_index field to the Elf_Scn struct which is updated when reading the section headers. This takes up space in every section and is hard to proof correct. In the case of using ELF_C_READ_MMAP the shndx_index field was only updated when the shdrs needed to be converted from file to memory order. And the two places were this function was used in readelf.c and elf-print-reloc-syms.c the wrong section was used to lookup the extended index table. There were also no tests for this functionality. Replace the elf_scnshndx implementation with a simpler lookup over all sections. This sounds inefficient, but in practice the SHT_SYMTAB_SHNDX section is the next section after the SHT_SYMTAB section. elf_scnshndx only needs to be called when there are more than SHN_LORESERVE (0xff00) sections. And normally a user would just lookup the SHT_SYMTAB and SHT_SYMTAB_SHNDX sections at the same time (which is what readelf does when showing the symbol table, as does nm, objcopy and libdwfl). Add a testfile manyfuncs.c that when compiled contains 64K symbols and sections. Make sure to use -fasynchronous-unwind-tables so there is at least one relocatable section that uses all function symbols (e.g. on arm32 where there is no .eh_frame by default). This can then be used to verify the readelf --relocs support. Add another test, test-manyfuncs that explicitly goes through the symbol table and associated extended index table and verify each function symbol matches the section name. There are For riscv there are local, notype, symbols at the start of each executable section which relocations refer to instead of the section symbol. Since all these local symbols are called ".L0" this isn't very useful, so print the section name instead. For powerpc ELFv1 all function symbols go through the .opd section. Allow this in the new test-manyfuncs test. * libelf/elf32_getshdr.c (load_shdr_wrlock): Remove handling of shndx_index. * libelf/elf_begin.c (file_read_elf): Likewise. * libelf/elf_scnshndx.c (elf_scnshndx): Rewritten. * libelf/libelf.h (elf_scnshndx): Added full documentation. * libelf/libelfP.h (struct Elf_Scn): Remove shndx_index field. (__elf_scnshndx_internal): Removed. * src/readelf.c (handle_relocs_rel): Use symscn in call to elf_scnshndx. Print section name for local start section label. (handle_relocs_rela): Likewise. * tests/Makefile.am (check_PROGRAMS): Add test-manyfuncs. (manyfuncs.o): New target. (check-local): New target, depends on manyfuncs.o. (TESTS): Add run-readelf-r-manyfuncs.sh and run-test-manyfuncs.sh. (EXTRA_DIST): Add run-readelf-r-manyfuncs.sh, run-test-manyfuncs.sh and manyfuncs.c. (test_manyfuncs_LDADD): New variable. (EXTRA_test_manyfuncs_DEPENDENCIES): New variable. (CLEANFILES): Add manyfuncs.o. * tests/elf-print-reloc-syms.c (print_reloc_symnames): Use symscn in call to elf_scnshndx. * tests/manyfuncs.c: New test file to generate 64K symbols and sections. * tests/run-readelf-r-manyfuncs.sh: New test wrapper. * tests/run-test-manyfuncs.sh: Likewise. * tests/test-manyfuncs.c: New test. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am26
-rw-r--r--tests/elf-print-reloc-syms.c4
-rw-r--r--tests/manyfuncs.c53
-rwxr-xr-xtests/run-readelf-r-manyfuncs.sh40
-rwxr-xr-xtests/run-test-manyfuncs.sh23
-rw-r--r--tests/test-manyfuncs.c343
6 files changed, 483 insertions, 6 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ec6cc901..335f1925 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -64,7 +64,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
getphdrnum leb128 read_unaligned \
msg_tst system-elf-libelf-test system-elf-gelf-test \
nvidia_extended_linemap_libdw elf-print-reloc-syms \
- cu-dwp-section-info declfiles \
+ cu-dwp-section-info declfiles test-manyfuncs \
$(asm_TESTS)
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
@@ -82,6 +82,16 @@ backtrace-child-biarch$(EXEEXT): backtrace-child.c
$(AM_LDFLAGS) $(LDFLAGS) $(backtrace_child_LDFLAGS) \
-o $@ $<
+# A test object with 64K sections and function symbols
+# Don't try to optimize or add debuginfo
+# Do explicitly add unwind tables, so there are definitely relocations
+# to all function symbols/sections.
+manyfuncs.o: manyfuncs.c
+ $(AM_V_CC)$(CC) -fasynchronous-unwind-tables -g0 -O0 -o $@ -c $<
+
+# We also want the manyfuncs.o (test) file generated
+check-local: manyfuncs.o
+
if GCOV
GCOV_FLAGS=-fprofile-arcs -ftest-coverage
else
@@ -142,6 +152,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
run-readelf-aranges.sh run-readelf-line.sh run-readelf-z.sh \
run-readelf-frames.sh \
run-readelf-n.sh \
+ run-readelf-r-manyfuncs.sh \
run-retain.sh \
run-native-test.sh run-bug1-test.sh \
run-debuglink.sh run-debugaltlink.sh run-buildid.sh \
@@ -217,7 +228,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
run-readelf-dw-form-indirect.sh run-strip-largealign.sh \
run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \
run-declfiles.sh \
- run-sysroot.sh
+ run-sysroot.sh \
+ run-test-manyfuncs.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
@@ -414,6 +426,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile_gnu_props.32be.o.bz2 \
testfile_gnu_props.64be.o.bz2 \
testfile-gnu-property-note-aarch64.bz2 \
+ run-readelf-r-manyfuncs.sh \
run-retain.sh testfile-retain.o.bz2 \
run-allfcts-multi.sh \
test-offset-loop.bz2 test-offset-loop.alt.bz2 \
@@ -688,7 +701,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile-dwp-4-cu-index-overflow.dwp.bz2 \
testfile-dwp-cu-index-overflow.source \
testfile-define-file.bz2 \
- testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh
+ testfile-sysroot.tar.bz2 run-sysroot.sh \
+ run-test-manyfuncs.sh manyfuncs.c \
+ run-debuginfod-seekable.sh
if USE_VALGRIND
@@ -869,6 +884,9 @@ nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw)
elf_print_reloc_syms_LDADD = $(libelf)
cu_dwp_section_info_LDADD = $(libdw)
declfiles_LDADD = $(libdw)
+test_manyfuncs_LDADD = $(libelf)
+# Make sure the manyfunc.o test object is generated before test-manyfuncs
+EXTRA_test_manyfuncs_DEPENDENCIES = manyfuncs.o
# We want to test the libelf headers against the system elf.h header.
# Don't include any -I CPPFLAGS. Except when we install our own elf.h.
@@ -888,7 +906,7 @@ system_elf_gelf_test_LDADD = $(libelf)
# A lock file used to make sure only one test dumps core at a time
MOSTLYCLEANFILES = core-dump-backtrace.lock
-CLEANFILES = $(BUILT_SOURCES)
+CLEANFILES = $(BUILT_SOURCES) manyfuncs.o
if GCOV
check: check-am coverage
diff --git a/tests/elf-print-reloc-syms.c b/tests/elf-print-reloc-syms.c
index b9453f6b..c3a8b073 100644
--- a/tests/elf-print-reloc-syms.c
+++ b/tests/elf-print-reloc-syms.c
@@ -43,8 +43,8 @@ print_reloc_symnames (Elf *elf, Elf_Scn *scn, GElf_Shdr *shdr, size_t sh_entsize
/* Search for the optional extended section index table. */
Elf_Data *xndxdata = NULL;
- int xndxscnidx = elf_scnshndx (scn);
- if (xndxscnidx)
+ int xndxscnidx = elf_scnshndx (symscn);
+ if (xndxscnidx > 0)
xndxdata = elf_getdata (elf_getscn (elf, xndxscnidx), NULL);
/* Get the section header string table index. */
diff --git a/tests/manyfuncs.c b/tests/manyfuncs.c
new file mode 100644
index 00000000..f76d2690
--- /dev/null
+++ b/tests/manyfuncs.c
@@ -0,0 +1,53 @@
+/* Test file for a binary with 64K+ sections and symbols.
+ Copyright (C) 2025 Mark J. Wielaard <[email protected]>
+ 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 <http://www.gnu.org/licenses/>. */
+
+
+/* We need a quoted string starting with a dot (the section name). */
+#define DQ(x) #x
+#define DOTQUOTE(x) DQ(.x)
+
+/* We want 2 * (8 ^ 5) = 2 * ((2 ^ 3) ^ 5) = 2 ^ 16 = 64K functions. */
+#define f(x) __attribute__ ((section (DOTQUOTE(x)))) void x(void) {};
+#define A(x) f(x##0) f(x##1) f(x##2) f(x##3) f(x##4) f(x##5) f(x##6) f(x##7)
+#define B(x) A(x##0) A(x##1) A(x##2) A(x##3) A(x##4) A(x##5) A(x##6) A(x##7)
+#define C(x) B(x##0) B(x##1) B(x##2) B(x##3) B(x##4) B(x##5) B(x##6) B(x##7)
+#define D(x) C(x##0) C(x##1) C(x##2) C(x##3) C(x##4) C(x##5) C(x##6) C(x##7)
+#define E(x) D(x##0) D(x##1) D(x##2) D(x##3) D(x##4) D(x##5) D(x##6) D(x##7)
+E(y)
+E(z)
+
+#undef f
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+
+/* Call all functions from main. */
+#define f(x) x();
+#define A(x) f(x##0) f(x##1) f(x##2) f(x##3) f(x##4) f(x##5) f(x##6) f(x##7)
+#define B(x) A(x##0) A(x##1) A(x##2) A(x##3) A(x##4) A(x##5) A(x##6) A(x##7)
+#define C(x) B(x##0) B(x##1) B(x##2) B(x##3) B(x##4) B(x##5) B(x##6) B(x##7)
+#define D(x) C(x##0) C(x##1) C(x##2) C(x##3) C(x##4) C(x##5) C(x##6) C(x##7)
+#define E(x) D(x##0) D(x##1) D(x##2) D(x##3) D(x##4) D(x##5) D(x##6) D(x##7)
+
+int
+main ()
+{
+E(y)
+E(z)
+}
diff --git a/tests/run-readelf-r-manyfuncs.sh b/tests/run-readelf-r-manyfuncs.sh
new file mode 100755
index 00000000..a7bb0478
--- /dev/null
+++ b/tests/run-readelf-r-manyfuncs.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+# Test readelf -r on file containing 64K+ functions and sections
+# Copyright (C) 2025 Mark J. Wielaard <[email protected]>
+# 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 <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# Tests readelf -r on file containing 64K+ functions and sections
+# This forces the use of elf_scnshndx to lookup section indexes
+# The test makes sure that for relocations against sectio symbols
+# the section names are resolved even for section indexes > 64K.
+#
+# Note the sections are named after the symbols (with a '.' in front).
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".y00000" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".z00000" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".y77777" || exit 1
+
+testrun ${abs_top_builddir}/src/readelf -r \
+ ${abs_top_builddir}/tests/manyfuncs.o | grep -F ".z77777" || exit 1
+
+exit 0
diff --git a/tests/run-test-manyfuncs.sh b/tests/run-test-manyfuncs.sh
new file mode 100755
index 00000000..110c599c
--- /dev/null
+++ b/tests/run-test-manyfuncs.sh
@@ -0,0 +1,23 @@
+#! /bin/sh
+# Copyright (C) 2025 Mark J. Wielaard <[email protected]>
+# 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 <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+testrun ${abs_top_builddir}/tests/test-manyfuncs \
+ ${abs_top_builddir}/tests/manyfuncs.o
+
+exit 0
diff --git a/tests/test-manyfuncs.c b/tests/test-manyfuncs.c
new file mode 100644
index 00000000..72569020
--- /dev/null
+++ b/tests/test-manyfuncs.c
@@ -0,0 +1,343 @@
+/* Test program for reading file with 64k+ sections and symbols.
+ Copyright (C) 2025 Mark J. Wielaard <[email protected]>
+ 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 <http://www.gnu.org/licenses/>. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "system.h"
+
+#include ELFUTILS_HEADER(elf)
+#include <gelf.h>
+
+/* Various fields (Elf_Half) can only contain up to 64k values. So
+ they need to be accessed through libelf functions which know where
+ the "true" value can be found. Also to get the section associated
+ with a symbol will need an extended symbol table entry. Use
+ elf_scnshndx to get at it and check we can get both symbol and
+ associated section names. */
+
+static void
+check_elf (const char *fname, bool use_mmap)
+{
+ printf ("\nfname (use_mmap: %d): %s\n", use_mmap, fname);
+
+ int fd = open (fname, O_RDONLY);
+ if (fd == -1)
+ {
+ printf ("cannot open `%s': %s\n", fname, strerror (errno));
+ exit (1);
+ }
+
+ Elf *elf = elf_begin (fd, use_mmap ? ELF_C_READ_MMAP : ELF_C_READ, NULL);
+ if (elf == NULL)
+ {
+ printf ("cannot create ELF descriptor: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* How many sections are there? */
+ size_t shnum;
+ if (elf_getshdrnum (elf, &shnum) < 0)
+ {
+ printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (shnum < SHN_LORESERVE)
+ {
+ printf ("Not enough section for test, %zd < %d\n",
+ shnum, SHN_LORESERVE);
+ exit (1);
+ }
+
+ printf ("shnum: %zd\n", shnum);
+
+ /* Get the section that contains the section header names. Check it
+ can be found and it contains the substring 'str' in its own
+ name. */
+ size_t shstrndx;
+ if (elf_getshdrstrndx (elf, &shstrndx) < 0)
+ {
+ printf ("elf_getshdrstrndx: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ Elf_Scn *scn = elf_getscn (elf, shstrndx);
+ if (scn == NULL)
+ {
+ printf ("cannot get section at index %zd: %s\n", shstrndx,
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("cannot get header for shstrndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* Assume the section name contains at least the substring "str". */
+ const char *sname = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (sname == NULL || strstr (sname, "str") == NULL)
+ {
+ printf ("Bad section name: %s\n", sname);
+ exit (1);
+ }
+
+ printf ("shstrndx section name: %s\n", sname);
+
+ /* The shstrndx section isn't a SYMTAB section, so elf_scnshndx will
+ return zero. */
+ int shndx = elf_scnshndx (scn);
+ if (shndx < 0)
+ {
+ printf ("elf_scnshndx error for shstrndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+ if (shndx > 0)
+ {
+ printf ("elf_scnshndx not zero for shstrndx section: %d\n", shndx);
+ exit (1);
+ }
+
+ /* Find the symtab and symtab_shndx by hand. */
+ size_t symtabndx = 0;
+ size_t symtabstrndx = 0;
+ size_t symtabsndx = 0;
+ size_t scns = 1; /* scn zero is skipped. */
+ Elf_Scn *symtabscn = NULL;
+ Elf_Scn *xndxscn = NULL;
+ scn = NULL;
+ while ((scn = elf_nextscn (elf, scn)) != NULL)
+ {
+ if (scns != elf_ndxscn (scn))
+ {
+ printf ("Unexpected elf_ndxscn %zd != %zd\n",
+ scns, elf_ndxscn (scn));
+ exit (1);
+ }
+
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("couldn't get shdr\n");
+ exit (1);
+ }
+
+ if (shdr->sh_type == SHT_SYMTAB)
+ {
+ symtabndx = elf_ndxscn (scn);
+ symtabstrndx = shdr->sh_link;
+ symtabscn = scn;
+ }
+
+ if (shdr->sh_type == SHT_SYMTAB_SHNDX)
+ {
+ symtabsndx = elf_ndxscn (scn);
+ xndxscn = scn;
+ }
+
+ /* We could break if we have both symtabndx and symtabsndx, but
+ we want to run through all sections to see if we get them
+ all and sanity check shnum. */
+ scns++;
+ }
+
+ printf ("scns: %zd\n", scns);
+ if (scns != shnum)
+ {
+ printf ("scns (%zd) != shnum (%zd)\n", scns, shnum);
+ exit (1);
+ }
+
+ printf ("symtabndx: %zd\n", symtabndx);
+ if (symtabndx == 0 || symtabscn == NULL)
+ {
+ printf ("No SYMTAB\n");
+ exit (1);
+ }
+
+ printf ("symtabsndx: %zd\n", symtabsndx);
+ if (symtabsndx == 0)
+ {
+ printf ("No SYMTAB_SNDX\n");
+ exit (1);
+ }
+
+ int scnshndx = elf_scnshndx (symtabscn);
+ printf ("scnshndx: %d\n", scnshndx);
+ if (scnshndx < 0)
+ {
+ printf ("elf_scnshndx failed: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (scnshndx == 0)
+ {
+ printf ("elf_scnshndx couldn't find scnshndx, returned zero\n");
+ exit (1);
+ }
+
+ if ((size_t) scnshndx != symtabsndx)
+ {
+ printf ("elf_scnshndx found wrong scnshndx (%d),"
+ " should have been (%zd)\n", scnshndx, symtabsndx);
+ exit (1);
+ }
+
+ Elf_Data *symdata = elf_getdata (symtabscn, NULL);
+ if (symdata == NULL)
+ {
+ printf ("Couldn't elf_getdata for symtabscn: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ size_t nsyms = symdata->d_size / (gelf_getclass (elf) == ELFCLASS32
+ ? sizeof (Elf32_Sym)
+ : sizeof (Elf64_Sym));
+
+ Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
+ if (xndxdata == NULL)
+ {
+ printf ("Couldn't elf_getdata for xndxscn: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ /* Now for every [yz]ddddd symbol , check that it matches the
+ section name (minus the starting dot). */
+ size_t yzsymcnt = 0;
+ for (size_t cnt = 0; cnt < nsyms; ++cnt)
+ {
+ const char *sym_name;
+ const char *section_name;
+ GElf_Word xndx;
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata, cnt,
+ &sym_mem, &xndx);
+
+ if (sym == NULL)
+ {
+ printf ("gelf_getsymshndx failed: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (sym->st_shndx != SHN_XINDEX)
+ xndx = sym->st_shndx;
+
+ sym_name = elf_strptr (elf, symtabstrndx, sym->st_name);
+ if (sym_name == NULL)
+ {
+ printf ("elf_strptr returned NULL for sym %zd: %s\n",
+ cnt, elf_errmsg (-1));
+ exit (1);
+ }
+
+ scn = elf_getscn (elf, xndx);
+ if (scn == NULL)
+ {
+ printf ("cannot get section at index %d: %s\n", xndx,
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ {
+ printf ("cannot get header for sym xndx section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ section_name = elf_strptr (elf, shstrndx, shdr->sh_name);
+ if (section_name == NULL)
+ {
+ printf ("elf_strptr returned NULL for section: %s\n",
+ elf_errmsg (-1));
+ exit (1);
+ }
+
+ if (GELF_ST_TYPE (sym->st_info) == STT_FUNC
+ && (sym_name[0] == 'y' || sym_name[0] == 'z')
+ && strlen (sym_name) == 6)
+ {
+ yzsymcnt++;
+ /* Every [yz]ddddd symbol comes from a section named after
+ the symbol prefixed with '.'. Except for powerpc ELFv1,
+ where all symbols point into the .opd. */
+ if ((section_name[0] != '.'
+ || strcmp (sym_name, &section_name[1]) != 0)
+ && strcmp (section_name, ".opd") != 0)
+ {
+ printf ("BAD SYM/SECTION %zd sym: %s, section: %s\n",
+ cnt, sym_name, section_name);
+ exit (1);
+ }
+ }
+ }
+
+#define YZSYMCNT (size_t) (2 * 8 * 8 * 8 * 8 * 8)
+ printf ("yzsymcnt: %zd\n", yzsymcnt);
+ if (yzsymcnt != YZSYMCNT)
+ {
+ printf ("Wrong number of yzsymcnts: %zd, should be %zd\n",
+ yzsymcnt, YZSYMCNT);
+ exit (1);
+ }
+
+ if (elf_end (elf) != 0)
+ {
+ printf ("failure in elf_end: %s\n", elf_errmsg (-1));
+ exit (1);
+ }
+
+ close (fd);
+}
+
+int
+main (int argc, char *argv[] __attribute__ ((unused)))
+{
+ elf_version (EV_CURRENT);
+
+ if (argc < 2)
+ {
+ printf ("Need at least one (file name) argument\n");
+ exit (1);
+ }
+
+ /* Test all file using ELF_C_READ and ELF_C_READ_MMAP. */
+ for (int i = 1; i < argc; i++)
+ {
+ check_elf (argv[i], false);
+ check_elf (argv[i], true);
+ }
+
+ return 0;
+}