From 9923a5e6b6a0eaf33faa696783bad6bd54d94714 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 14 Aug 2012 17:00:08 +0200 Subject: [PATCH] Add support for archives with 64-bit symbol tables (#843019) --- elfutils-0.154-sym64.patch | 336 +++++++++++++++++++++++++++++++++++++ elfutils.spec | 7 +- 2 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 elfutils-0.154-sym64.patch diff --git a/elfutils-0.154-sym64.patch b/elfutils-0.154-sym64.patch new file mode 100644 index 0000000..a88b9a4 --- /dev/null +++ b/elfutils-0.154-sym64.patch @@ -0,0 +1,336 @@ +diff --git a/libdwfl/offline.c b/libdwfl/offline.c +index a142acd..26a6bd6 100644 +--- a/libdwfl/offline.c ++++ b/libdwfl/offline.c +@@ -1,5 +1,5 @@ + /* Recover relocatibility for addresses computed from debug information. +- Copyright (C) 2005, 2006, 2007, 2008, 2009 Red Hat, Inc. ++ Copyright (C) 2005-2009, 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify +@@ -169,7 +169,8 @@ process_archive_member (Dwfl *dwfl, const char *name, const char *file_name, + return ELF_C_NULL; + } + +- if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//")) ++ if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//") ++ || !strcmp (h->ar_name, "/SYM64/")) + { + skip:; + /* Skip this and go to the next. */ +diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c +index 5cd2f07..b9d5cea 100644 +--- a/libelf/elf_begin.c ++++ b/libelf/elf_begin.c +@@ -1,5 +1,5 @@ + /* Create descriptor for processing file. +- Copyright (C) 1998-2010 Red Hat, Inc. ++ Copyright (C) 1998-2010, 2012 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper , 1998. + +@@ -787,6 +787,10 @@ __libelf_next_arhdr_wrlock (elf) + && memcmp (ar_hdr->ar_name, "/ ", 16) == 0) + /* This is the index. */ + elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2); ++ else if (ar_hdr->ar_name[1] == 'S' ++ && memcmp (ar_hdr->ar_name, "/SYM64/ ", 16) == 0) ++ /* 64-bit index. */ ++ elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/SYM64/", 8); + else if (ar_hdr->ar_name[1] == '/' + && memcmp (ar_hdr->ar_name, "// ", 16) == 0) + /* This is the array with the long names. */ +diff --git a/libelf/elf_getarsym.c b/libelf/elf_getarsym.c +index eafaef5..9e0f4c2 100644 +--- a/libelf/elf_getarsym.c ++++ b/libelf/elf_getarsym.c +@@ -1,5 +1,5 @@ + /* Return symbol table of archive. +- Copyright (C) 1998, 1999, 2000, 2002, 2005 Red Hat, Inc. ++ Copyright (C) 1998-2000, 2002, 2005, 2012 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper , 1998. + +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -45,6 +46,31 @@ + #include "libelfP.h" + + ++static int ++read_number_entries (uint64_t *nump, Elf *elf, size_t *offp, bool index64_p) ++{ ++ union u ++ { ++ uint64_t ret64; ++ uint32_t ret32; ++ } u; ++ ++ size_t w = index64_p ? 8 : 4; ++ if (elf->map_address != NULL) ++ u = *(union u *) (elf->map_address + *offp); ++ else if ((size_t) pread_retry (elf->fildes, &u, w, *offp) != w) ++ return -1; ++ ++ *offp += w; ++ ++ if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ *nump = index64_p ? bswap_64 (u.ret64) : bswap_32 (u.ret32); ++ else ++ *nump = index64_p ? u.ret64 : u.ret32; ++ ++ return 0; ++} ++ + Elf_Arsym * + elf_getarsym (elf, ptr) + Elf *elf; +@@ -116,11 +142,17 @@ elf_getarsym (elf, ptr) + goto out; + } + +- /* Now test whether this is the index. It is denoted by the +- name being "/ ". ++ bool index64_p; ++ /* Now test whether this is the index. If the name is "/", this ++ is 32-bit index, if it's "/SYM64/", it's 64-bit index. ++ + XXX This is not entirely true. There are some more forms. + Which of them shall we handle? */ +- if (memcmp (index_hdr->ar_name, "/ ", 16) != 0) ++ if (memcmp (index_hdr->ar_name, "/ ", 16) == 0) ++ index64_p = false; ++ else if (memcmp (index_hdr->ar_name, "/SYM64/ ", 16) == 0) ++ index64_p = true; ++ else + { + /* If the index is not the first entry, there is no index. + +@@ -128,27 +160,18 @@ elf_getarsym (elf, ptr) + __libelf_seterrno (ELF_E_NO_INDEX); + goto out; + } ++ int w = index64_p ? 8 : 4; + + /* We have an archive. The first word in there is the number of + entries in the table. */ +- uint32_t n; +- if (elf->map_address == NULL) ++ uint64_t n; ++ size_t off = elf->start_offset + SARMAG + sizeof (struct ar_hdr); ++ if (read_number_entries (&n, elf, &off, index64_p) < 0) + { +- if (pread_retry (elf->fildes, &n, sizeof (n), +- elf->start_offset + SARMAG + sizeof (struct ar_hdr)) +- != sizeof (n)) +- { +- /* Cannot read the number of entries. */ +- __libelf_seterrno (ELF_E_NO_INDEX); +- goto out; +- } ++ /* Cannot read the number of entries. */ ++ __libelf_seterrno (ELF_E_NO_INDEX); ++ goto out; + } +- else +- n = *(uint32_t *) (elf->map_address + elf->start_offset +- + SARMAG + sizeof (struct ar_hdr)); +- +- if (__BYTE_ORDER == __LITTLE_ENDIAN) +- n = bswap_32 (n); + + /* Now we can perform some first tests on whether all the data + needed for the index is available. */ +@@ -158,7 +181,7 @@ elf_getarsym (elf, ptr) + #if SIZE_MAX <= 4294967295U + || n >= SIZE_MAX / sizeof (Elf_Arsym) + #endif +- || n * sizeof (uint32_t) > index_size) ++ || n * w > index_size) + { + /* This index table cannot be right since it does not fit into + the file. */ +@@ -171,14 +194,19 @@ elf_getarsym (elf, ptr) + elf->state.ar.ar_sym = (Elf_Arsym *) malloc (ar_sym_len); + if (elf->state.ar.ar_sym != NULL) + { +- uint32_t *file_data; ++ union ++ { ++ uint32_t u32[n]; ++ uint64_t u64[n]; ++ } *file_data; + char *str_data; ++ size_t sz = n * w; + + if (elf->map_address == NULL) + { +- file_data = (uint32_t *) alloca (n * sizeof (uint32_t)); ++ file_data = alloca (sz); + +- ar_sym_len += index_size - n * sizeof (uint32_t); ++ ar_sym_len += index_size - n * w; + Elf_Arsym *newp = (Elf_Arsym *) realloc (elf->state.ar.ar_sym, + ar_sym_len); + if (newp == NULL) +@@ -193,18 +221,10 @@ elf_getarsym (elf, ptr) + char *new_str = (char *) (elf->state.ar.ar_sym + n + 1); + + /* Now read the data from the file. */ +- if ((size_t) pread_retry (elf->fildes, file_data, +- n * sizeof (uint32_t), +- elf->start_offset + SARMAG +- + sizeof (struct ar_hdr) +- + sizeof (uint32_t)) +- != n * sizeof (uint32_t) ++ if ((size_t) pread_retry (elf->fildes, file_data, sz, off) != sz + || ((size_t) pread_retry (elf->fildes, new_str, +- index_size - n * sizeof (uint32_t), +- elf->start_offset +- + SARMAG + sizeof (struct ar_hdr) +- + (n + 1) * sizeof (uint32_t)) +- != index_size - n * sizeof (uint32_t))) ++ index_size - sz, off + sz) ++ != index_size - sz)) + { + /* We were not able to read the data. */ + free (elf->state.ar.ar_sym); +@@ -217,10 +237,8 @@ elf_getarsym (elf, ptr) + } + else + { +- file_data = (uint32_t *) (elf->map_address + elf->start_offset +- + SARMAG + sizeof (struct ar_hdr) +- + sizeof (uint32_t)); +- str_data = (char *) &file_data[n]; ++ file_data = (void *) (elf->map_address + off); ++ str_data = (char *) (elf->map_address + off + sz); + } + + /* Now we can build the data structure. */ +@@ -228,13 +246,38 @@ elf_getarsym (elf, ptr) + for (size_t cnt = 0; cnt < n; ++cnt) + { + arsym[cnt].as_name = str_data; +- if (__BYTE_ORDER == __LITTLE_ENDIAN) +- arsym[cnt].as_off = bswap_32 (file_data[cnt]); ++ if (index64_p) ++ { ++ uint64_t tmp = file_data->u64[cnt]; ++ if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ tmp = bswap_64 (tmp); ++ ++ arsym[cnt].as_off = tmp; ++ ++ /* Check whether 64-bit offset fits into 32-bit ++ size_t. */ ++ if (sizeof (arsym[cnt].as_off) < 8 ++ && arsym[cnt].as_off != tmp) ++ { ++ if (elf->map_address == NULL) ++ { ++ free (elf->state.ar.ar_sym); ++ elf->state.ar.ar_sym = NULL; ++ } ++ ++ __libelf_seterrno (ELF_E_RANGE); ++ goto out; ++ } ++ } ++ else if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ arsym[cnt].as_off = bswap_32 (file_data->u32[cnt]); + else +- arsym[cnt].as_off = file_data[cnt]; ++ arsym[cnt].as_off = file_data->u32[cnt]; ++ + arsym[cnt].as_hash = _dl_elf_hash (str_data); + str_data = rawmemchr (str_data, '\0') + 1; + } ++ + /* At the end a special entry. */ + arsym[n].as_name = NULL; + arsym[n].as_off = 0; +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 0615869..d0f4e80 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -83,7 +83,8 @@ + run-early-offscn.sh run-dwarf-getmacros.sh \ + run-test-flag-nobits.sh run-prelink-addr-test.sh \ + run-dwarf-getstring.sh run-rerequest_tag.sh run-typeiter.sh \ +- run-readelf-d.sh run-unstrip-n.sh run-low_high_pc.sh ++ run-readelf-d.sh run-unstrip-n.sh run-low_high_pc.sh \ ++ run-test-archive64.sh + + if !STANDALONE + noinst_PROGRAMS += msg_tst md5-sha1-test +@@ -167,7 +168,8 @@ + run-typeiter.sh testfile59.bz2 \ + run-readelf-d.sh testlib_dynseg.so.bz2 \ + run-unstrip-n.sh testcore-rtlib.bz2 \ +- run-low_high_pc.sh testfile_low_high_pc.bz2 ++ run-low_high_pc.sh testfile_low_high_pc.bz2 \ ++ run-test-archive64.sh testarchive64.a.bz2 + + installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \ + bindir=$(DESTDIR)$(bindir) \ +diff --git a/tests/run-test-archive64.sh b/tests/run-test-archive64.sh +new file mode 100755 +index 0000000..26552ac +--- /dev/null ++++ b/tests/run-test-archive64.sh +@@ -0,0 +1,43 @@ ++#! /bin/sh ++# Copyright (C) 2012 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 ++ ++# The test archive was produced on an s390x machine using the ++# following command sequence: ++# echo 'int aaa(void){}' | gcc -x c /dev/stdin -c -o aaa.o ++# echo 'int bbb(void){} int bbb2(void){}' | gcc -x c /dev/stdin -c -o bbb.o ++# echo 'int ccc(void){} int ccc2(void){} int ccc3(void){}' \ ++# | gcc -x c /dev/stdin -c -o ccc.o ++# ar cru testarchive64.a aaa.o bbb.o ccc.o ++testfiles testarchive64.a ++ ++testrun_compare ../src/readelf -c testarchive64.a <<\EOF ++ ++Index of archive 'testarchive64.a' has 7 entries: ++Archive member 'aaa.o' contains: ++ aaa ++Archive member 'bbb.o' contains: ++ bbb ++ bbb2 ++Archive member 'ccc.o' contains: ++ ccc ++ ccc2 ++ ccc3 ++EOF ++ ++exit 0 +diff --git a/tests/testarchive64.a.bz2 b/tests/testarchive64.a.bz2 +new file mode 100644 +index 0000000..4b54603 +Binary files /dev/null and b/tests/testarchive64.a.bz2 differ diff --git a/elfutils.spec b/elfutils.spec index c0d249a..7bea5c2 100644 --- a/elfutils.spec +++ b/elfutils.spec @@ -1,7 +1,7 @@ Name: elfutils Summary: A collection of utilities and DSOs to handle compiled objects Version: 0.154 -%global baserelease 3 +%global baserelease 4 URL: https://fedorahosted.org/elfutils/ %global source_url http://fedorahosted.org/releases/e/l/elfutils/%{version}/ License: GPLv3+ and (GPLv2+ or LGPLv3+) @@ -48,6 +48,7 @@ Patch2: %{?source_url}elfutils-portability.patch Patch3: elfutils-0.154-binutils-pr-ld-13621.patch Patch4: elfutils-0.154-xlatetom-835877.patch Patch5: elfutils-0.154-dwz.patch +Patch6: elfutils-0.154-sym64.patch %if !%{compat} Release: %{baserelease}%{?dist} @@ -215,6 +216,7 @@ sed -i.scanf-m -e 's/%m/%a/g' src/addr2line.c tests/line2addr.c %patch3 -p1 -b .binutils-pr-ld-13621 %patch4 -p1 -b .xlatetom-835877 %patch5 -p1 -b .dwz +%patch6 -p1 -b .sym64 find . -name \*.sh ! -perm -0100 -print | xargs chmod +x @@ -331,6 +333,9 @@ rm -rf ${RPM_BUILD_ROOT} %{_libdir}/libelf.a %changelog +* Tue Aug 14 2012 Petr Machata - 0.154-4 +- Add support for archives with 64-bit symbol tables (#843019) + * Wed Aug 01 2012 Mark Wielaard 0.154-3 - Add dwz support