--- /dev/null
+#!/bin/sh -e
+## 304_pr4476.dpatch
+##
+## DP: Description: Fix PR binutils/4476
+## DP: Upstream status: Not yet accepted in CVS head
+
+if [ $# -ne 1 ]; then
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1
+fi
+
+[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
+patch_opts="${patch_opts:--f --no-backup-if-mismatch}"
+
+case "$1" in
+ -patch) patch $patch_opts -p1 < $0;;
+ -unpatch) patch $patch_opts -p1 -R < $0;;
+ *)
+ echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
+ exit 1;;
+esac
+
+exit 0
+
+binutils/
+
+2007-05-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR binutils/4476
+ * readelf.c (print_dynamic_symbol): New.
+ (process_symbol_table): Handle DT_GNU_HASH for dynamic symbols.
+
+ld/testsuite/
+
+2007-05-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR binutils/4476
+ * ld-elf/hash.d: Check "-s -D" for readelf.
+
+@DPATCH@
+--- binutils/binutils/readelf.c.hash 2007-05-09 10:54:22.000000000 -0700
++++ binutils/binutils/readelf.c 2007-05-09 17:24:46.000000000 -0700
+@@ -7033,6 +7033,39 @@ get_dynamic_data (FILE *file, unsigned i
+ return i_data;
+ }
+
++static void
++print_dynamic_symbol (bfd_vma si, unsigned long hn)
++{
++ Elf_Internal_Sym *psym;
++ int n;
++
++ psym = dynamic_symbols + si;
++
++ n = print_vma (si, DEC_5);
++ if (n < 5)
++ fputs (" " + n, stdout);
++ printf (" %3lu: ", hn);
++ print_vma (psym->st_value, LONG_HEX);
++ putchar (' ');
++ print_vma (psym->st_size, DEC_5);
++
++ printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
++ printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
++ printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
++ /* Check to see if any other bits in the st_other field are set.
++ Note - displaying this information disrupts the layout of the
++ table being generated, but for the moment this case is very
++ rare. */
++ if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
++ printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
++ printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
++ if (VALID_DYNAMIC_NAME (psym->st_name))
++ print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
++ else
++ printf (" <corrupt: %14ld>", psym->st_name);
++ putchar ('\n');
++}
++
+ /* Dump the symbol table. */
+ static int
+ process_symbol_table (FILE *file)
+@@ -7045,12 +7078,14 @@ process_symbol_table (FILE *file)
+ bfd_vma ngnubuckets = 0;
+ bfd_vma *gnubuckets = NULL;
+ bfd_vma *gnuchains = NULL;
++ bfd_vma gnusymidx = 0;
+
+ if (! do_syms && !do_histogram)
+ return 1;
+
+- if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL)
+- || do_histogram))
++ if (dynamic_info[DT_HASH]
++ && (do_histogram
++ || (do_using_dynamic && dynamic_strings != NULL)))
+ {
+ unsigned char nb[8];
+ unsigned char nc[8];
+@@ -7094,54 +7129,157 @@ process_symbol_table (FILE *file)
+ return 0;
+ }
+
+- if (do_syms
+- && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL)
++ if (dynamic_info_DT_GNU_HASH
++ && (do_histogram
++ || (do_using_dynamic && dynamic_strings != NULL)))
+ {
+- unsigned long hn;
+- bfd_vma si;
++ unsigned char nb[16];
++ bfd_vma i, maxchain = 0xffffffff, bitmaskwords;
++ bfd_vma buckets_vma;
++
++ if (fseek (file,
++ (archive_file_offset
++ + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
++ sizeof nb)),
++ SEEK_SET))
++ {
++ error (_("Unable to seek to start of dynamic information\n"));
++ return 0;
++ }
++
++ if (fread (nb, 16, 1, file) != 1)
++ {
++ error (_("Failed to read in number of buckets\n"));
++ return 0;
++ }
+
+- printf (_("\nSymbol table for image:\n"));
++ ngnubuckets = byte_get (nb, 4);
++ gnusymidx = byte_get (nb + 4, 4);
++ bitmaskwords = byte_get (nb + 8, 4);
++ buckets_vma = dynamic_info_DT_GNU_HASH + 16;
+ if (is_32bit_elf)
+- printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++ buckets_vma += bitmaskwords * 4;
+ else
+- printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++ buckets_vma += bitmaskwords * 8;
+
+- for (hn = 0; hn < nbuckets; hn++)
++ if (fseek (file,
++ (archive_file_offset
++ + offset_from_vma (file, buckets_vma, 4)),
++ SEEK_SET))
+ {
+- if (! buckets[hn])
+- continue;
++ error (_("Unable to seek to start of dynamic information\n"));
++ return 0;
++ }
++
++ gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
++
++ if (gnubuckets == NULL)
++ return 0;
++
++ for (i = 0; i < ngnubuckets; i++)
++ if (gnubuckets[i] != 0)
++ {
++ if (gnubuckets[i] < gnusymidx)
++ return 0;
++
++ if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
++ maxchain = gnubuckets[i];
++ }
++
++ if (maxchain == 0xffffffff)
++ return 0;
+
+- for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
++ maxchain -= gnusymidx;
++
++ if (fseek (file,
++ (archive_file_offset
++ + offset_from_vma (file, buckets_vma
++ + 4 * (ngnubuckets + maxchain), 4)),
++ SEEK_SET))
++ {
++ error (_("Unable to seek to start of dynamic information\n"));
++ return 0;
++ }
++
++ do
++ {
++ if (fread (nb, 4, 1, file) != 1)
+ {
+- Elf_Internal_Sym *psym;
+- int n;
++ error (_("Failed to determine last chain length\n"));
++ return 0;
++ }
+
+- psym = dynamic_symbols + si;
++ if (maxchain + 1 == 0)
++ return 0;
+
+- n = print_vma (si, DEC_5);
+- if (n < 5)
+- fputs (" " + n, stdout);
+- printf (" %3lu: ", hn);
+- print_vma (psym->st_value, LONG_HEX);
+- putchar (' ');
+- print_vma (psym->st_size, DEC_5);
++ ++maxchain;
++ }
++ while ((byte_get (nb, 4) & 1) == 0);
+
+- printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
+- printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
+- printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
+- /* Check to see if any other bits in the st_other field are set.
+- Note - displaying this information disrupts the layout of the
+- table being generated, but for the moment this case is very rare. */
+- if (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other))
+- printf (" [%s] ", get_symbol_other (psym->st_other ^ ELF_ST_VISIBILITY (psym->st_other)));
+- printf (" %3.3s ", get_symbol_index_type (psym->st_shndx));
+- if (VALID_DYNAMIC_NAME (psym->st_name))
+- print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
+- else
+- printf (" <corrupt: %14ld>", psym->st_name);
+- putchar ('\n');
++ if (fseek (file,
++ (archive_file_offset
++ + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
++ SEEK_SET))
++ {
++ error (_("Unable to seek to start of dynamic information\n"));
++ return 0;
++ }
++
++ gnuchains = get_dynamic_data (file, maxchain, 4);
++
++ if (gnuchains == NULL)
++ return 0;
++ }
++
++ if ((dynamic_info[DT_HASH] || dynamic_info_DT_GNU_HASH)
++ && do_syms
++ && do_using_dynamic
++ && dynamic_strings != NULL)
++ {
++ unsigned long hn;
++
++ if (dynamic_info[DT_HASH])
++ {
++ bfd_vma si;
++
++ printf (_("\nSymbol table for image:\n"));
++ if (is_32bit_elf)
++ printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++ else
++ printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++
++ for (hn = 0; hn < nbuckets; hn++)
++ {
++ if (! buckets[hn])
++ continue;
++
++ for (si = buckets[hn]; si < nchains && si > 0; si = chains[si])
++ print_dynamic_symbol (si, hn);
+ }
+ }
++
++ if (dynamic_info_DT_GNU_HASH)
++ {
++ printf (_("\nSymbol table of `.gnu.hash' for image:\n"));
++ if (is_32bit_elf)
++ printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++ else
++ printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
++
++ for (hn = 0; hn < ngnubuckets; ++hn)
++ if (gnubuckets[hn] != 0)
++ {
++ bfd_vma si = gnubuckets[hn];
++ bfd_vma off = si - gnusymidx;
++
++ do
++ {
++ print_dynamic_symbol (si, hn);
++ si++;
++ }
++ while ((gnuchains[off++] & 1) == 0);
++ }
++ }
+ }
+ else if (do_syms && !do_using_dynamic)
+ {
+@@ -7426,108 +7564,12 @@ process_symbol_table (FILE *file)
+
+ if (do_histogram && dynamic_info_DT_GNU_HASH)
+ {
+- unsigned char nb[16];
+- bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords;
+ unsigned long *lengths;
+ unsigned long *counts;
+ unsigned long hn;
+ unsigned long maxlength = 0;
+ unsigned long nzero_counts = 0;
+ unsigned long nsyms = 0;
+- bfd_vma buckets_vma;
+-
+- if (fseek (file,
+- (archive_file_offset
+- + offset_from_vma (file, dynamic_info_DT_GNU_HASH,
+- sizeof nb)),
+- SEEK_SET))
+- {
+- error (_("Unable to seek to start of dynamic information\n"));
+- return 0;
+- }
+-
+- if (fread (nb, 16, 1, file) != 1)
+- {
+- error (_("Failed to read in number of buckets\n"));
+- return 0;
+- }
+-
+- ngnubuckets = byte_get (nb, 4);
+- symidx = byte_get (nb + 4, 4);
+- bitmaskwords = byte_get (nb + 8, 4);
+- buckets_vma = dynamic_info_DT_GNU_HASH + 16;
+- if (is_32bit_elf)
+- buckets_vma += bitmaskwords * 4;
+- else
+- buckets_vma += bitmaskwords * 8;
+-
+- if (fseek (file,
+- (archive_file_offset
+- + offset_from_vma (file, buckets_vma, 4)),
+- SEEK_SET))
+- {
+- error (_("Unable to seek to start of dynamic information\n"));
+- return 0;
+- }
+-
+- gnubuckets = get_dynamic_data (file, ngnubuckets, 4);
+-
+- if (gnubuckets == NULL)
+- return 0;
+-
+- for (i = 0; i < ngnubuckets; i++)
+- if (gnubuckets[i] != 0)
+- {
+- if (gnubuckets[i] < symidx)
+- return 0;
+-
+- if (maxchain == 0xffffffff || gnubuckets[i] > maxchain)
+- maxchain = gnubuckets[i];
+- }
+-
+- if (maxchain == 0xffffffff)
+- return 0;
+-
+- maxchain -= symidx;
+-
+- if (fseek (file,
+- (archive_file_offset
+- + offset_from_vma (file, buckets_vma
+- + 4 * (ngnubuckets + maxchain), 4)),
+- SEEK_SET))
+- {
+- error (_("Unable to seek to start of dynamic information\n"));
+- return 0;
+- }
+-
+- do
+- {
+- if (fread (nb, 4, 1, file) != 1)
+- {
+- error (_("Failed to determine last chain length\n"));
+- return 0;
+- }
+-
+- if (maxchain + 1 == 0)
+- return 0;
+-
+- ++maxchain;
+- }
+- while ((byte_get (nb, 4) & 1) == 0);
+-
+- if (fseek (file,
+- (archive_file_offset
+- + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
+- SEEK_SET))
+- {
+- error (_("Unable to seek to start of dynamic information\n"));
+- return 0;
+- }
+-
+- gnuchains = get_dynamic_data (file, maxchain, 4);
+-
+- if (gnuchains == NULL)
+- return 0;
+
+ lengths = calloc (ngnubuckets, sizeof (*lengths));
+ if (lengths == NULL)
+@@ -7545,7 +7587,7 @@ process_symbol_table (FILE *file)
+ {
+ bfd_vma off, length = 1;
+
+- for (off = gnubuckets[hn] - symidx;
++ for (off = gnubuckets[hn] - gnusymidx;
+ (gnuchains[off] & 1) == 0; ++off)
+ ++length;
+ lengths[hn] = length;
+--- binutils/ld/testsuite/ld-elf/hash.d.hash 2006-09-15 07:55:42.000000000 -0700
++++ binutils/ld/testsuite/ld-elf/hash.d 2007-05-09 15:46:56.000000000 -0700
+@@ -1,5 +1,5 @@
+ #source: start.s
+-#readelf: -d
++#readelf: -d -s -D
+ #ld: -shared --hash-style=gnu
+ #target: *-*-linux*
+ #notarget: mips*-*-*
+@@ -7,3 +7,11 @@
+ #...
+ [ ]*0x[0-9a-z]+[ ]+\(GNU_HASH\)[ ]+0x[0-9a-z]+
+ #...
++[ ]+[0-9]+[ ]+[0-9]+:[ ]+[0-9a-f]+[ ]+[0-9]+[ ]+NOTYPE[ ]+GLOBAL DEFAULT[ ]+[1-9] _start
++#...
++[ ]+[0-9]+[ ]+[0-9]+:[ ]+[0-9a-f]+[ ]+[0-9]+[ ]+NOTYPE[ ]+GLOBAL DEFAULT[ ]+[1-9] main
++#...
++[ ]+[0-9]+[ ]+[0-9]+:[ ]+[0-9a-f]+[ ]+[0-9]+[ ]+NOTYPE[ ]+GLOBAL DEFAULT[ ]+[1-9] start
++#...
++[ ]+[0-9]+[ ]+[0-9]+:[ ]+[0-9a-f]+[ ]+[0-9]+[ ]+NOTYPE[ ]+GLOBAL DEFAULT[ ]+[1-9] __start
++#...