Automatic date update in version.in
[binutils-gdb.git] / bfd / elf-strtab.c
index 673b9d77ac98d5e36b46d910ceb01ec0e3708883..ea30a6e638d3b864f68e030db55b3b7edd0fdafc 100644 (file)
@@ -1,12 +1,12 @@
 /* ELF strtab with GC and suffix merging support.
 /* ELF strtab with GC and suffix merging support.
-   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2001-2022 Free Software Foundation, Inc.
    Written by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Written by Jakub Jelinek <jakub@redhat.com>.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program 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 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 
-#include "bfd.h"
 #include "sysdep.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "hashtab.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "hashtab.h"
@@ -47,9 +48,9 @@ struct elf_strtab_hash
 {
   struct bfd_hash_table table;
   /* Next available index.  */
 {
   struct bfd_hash_table table;
   /* Next available index.  */
-  bfd_size_type size;
+  size_t size;
   /* Number of array entries alloced.  */
   /* Number of array entries alloced.  */
-  bfd_size_type alloced;
+  size_t alloced;
   /* Final strtab size.  */
   bfd_size_type sec_size;
   /* Array of pointers to strtab entries.  */
   /* Final strtab size.  */
   bfd_size_type sec_size;
   /* Array of pointers to strtab entries.  */
@@ -66,7 +67,8 @@ elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
   if (entry == NULL)
   /* Allocate the structure if it has not already been allocated by a
      subclass.  */
   if (entry == NULL)
-    entry = bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
+    entry = (struct bfd_hash_entry *)
+       bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
   if (entry == NULL)
     return NULL;
 
   if (entry == NULL)
     return NULL;
 
@@ -93,13 +95,14 @@ struct elf_strtab_hash *
 _bfd_elf_strtab_init (void)
 {
   struct elf_strtab_hash *table;
 _bfd_elf_strtab_init (void)
 {
   struct elf_strtab_hash *table;
-  bfd_size_type amt = sizeof (struct elf_strtab_hash);
+  size_t amt = sizeof (struct elf_strtab_hash);
 
 
-  table = bfd_malloc (amt);
+  table = (struct elf_strtab_hash *) bfd_malloc (amt);
   if (table == NULL)
     return NULL;
 
   if (table == NULL)
     return NULL;
 
-  if (! bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc))
+  if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
+                           sizeof (struct elf_strtab_hash_entry)))
     {
       free (table);
       return NULL;
     {
       free (table);
       return NULL;
@@ -109,7 +112,8 @@ _bfd_elf_strtab_init (void)
   table->size = 1;
   table->alloced = 64;
   amt = sizeof (struct elf_strtab_hasn_entry *);
   table->size = 1;
   table->alloced = 64;
   amt = sizeof (struct elf_strtab_hasn_entry *);
-  table->array = bfd_malloc (table->alloced * amt);
+  table->array = ((struct elf_strtab_hash_entry **)
+                 bfd_malloc (table->alloced * amt));
   if (table->array == NULL)
     {
       free (table);
   if (table->array == NULL)
     {
       free (table);
@@ -134,10 +138,10 @@ _bfd_elf_strtab_free (struct elf_strtab_hash *tab)
 /* Get the index of an entity in a hash table, adding it if it is not
    already present.  */
 
 /* Get the index of an entity in a hash table, adding it if it is not
    already present.  */
 
-bfd_size_type
+size_t
 _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
                     const char *str,
 _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
                     const char *str,
-                    bfd_boolean copy)
+                    bool copy)
 {
   register struct elf_strtab_hash_entry *entry;
 
 {
   register struct elf_strtab_hash_entry *entry;
 
@@ -148,10 +152,10 @@ _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
 
   BFD_ASSERT (tab->sec_size == 0);
   entry = (struct elf_strtab_hash_entry *)
 
   BFD_ASSERT (tab->sec_size == 0);
   entry = (struct elf_strtab_hash_entry *)
-         bfd_hash_lookup (&tab->table, str, TRUE, copy);
+         bfd_hash_lookup (&tab->table, str, true, copy);
 
   if (entry == NULL)
 
   if (entry == NULL)
-    return (bfd_size_type) -1;
+    return (size_t) -1;
 
   entry->refcount++;
   if (entry->len == 0)
 
   entry->refcount++;
   if (entry->len == 0)
@@ -163,9 +167,10 @@ _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
        {
          bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
          tab->alloced *= 2;
        {
          bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
          tab->alloced *= 2;
-         tab->array = bfd_realloc (tab->array, tab->alloced * amt);
+         tab->array = (struct elf_strtab_hash_entry **)
+             bfd_realloc_or_free (tab->array, tab->alloced * amt);
          if (tab->array == NULL)
          if (tab->array == NULL)
-           return (bfd_size_type) -1;
+           return (size_t) -1;
        }
 
       entry->u.index = tab->size++;
        }
 
       entry->u.index = tab->size++;
@@ -175,9 +180,9 @@ _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
 }
 
 void
 }
 
 void
-_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
+_bfd_elf_strtab_addref (struct elf_strtab_hash *tab, size_t idx)
 {
 {
-  if (idx == 0 || idx == (bfd_size_type) -1)
+  if (idx == 0 || idx == (size_t) -1)
     return;
   BFD_ASSERT (tab->sec_size == 0);
   BFD_ASSERT (idx < tab->size);
     return;
   BFD_ASSERT (tab->sec_size == 0);
   BFD_ASSERT (idx < tab->size);
@@ -185,9 +190,9 @@ _bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
 }
 
 void
 }
 
 void
-_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
+_bfd_elf_strtab_delref (struct elf_strtab_hash *tab, size_t idx)
 {
 {
-  if (idx == 0 || idx == (bfd_size_type) -1)
+  if (idx == 0 || idx == (size_t) -1)
     return;
   BFD_ASSERT (tab->sec_size == 0);
   BFD_ASSERT (idx < tab->size);
     return;
   BFD_ASSERT (tab->sec_size == 0);
   BFD_ASSERT (idx < tab->size);
@@ -195,15 +200,73 @@ _bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
   --tab->array[idx]->refcount;
 }
 
   --tab->array[idx]->refcount;
 }
 
+unsigned int
+_bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, size_t idx)
+{
+  return tab->array[idx]->refcount;
+}
+
 void
 _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
 {
 void
 _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
 {
-  bfd_size_type idx;
+  size_t idx;
 
 
-  for (idx = 1; idx < tab->size; ++idx)
+  for (idx = 1; idx < tab->size; idx++)
     tab->array[idx]->refcount = 0;
 }
 
     tab->array[idx]->refcount = 0;
 }
 
+/* Save strtab refcounts prior to adding --as-needed library.  */
+
+struct strtab_save
+{
+  size_t size;
+  unsigned int refcount[1];
+};
+
+void *
+_bfd_elf_strtab_save (struct elf_strtab_hash *tab)
+{
+  struct strtab_save *save;
+  size_t idx, size;
+
+  size = sizeof (*save) + (tab->size - 1) * sizeof (save->refcount[0]);
+  save = bfd_malloc (size);
+  if (save == NULL)
+    return save;
+
+  save->size = tab->size;
+  for (idx = 1; idx < tab->size; idx++)
+    save->refcount[idx] = tab->array[idx]->refcount;
+  return save;
+}
+
+/* Restore strtab refcounts on finding --as-needed library not needed.  */
+
+void
+_bfd_elf_strtab_restore (struct elf_strtab_hash *tab, void *buf)
+{
+  size_t idx, curr_size = tab->size, save_size;
+  struct strtab_save *save = (struct strtab_save *) buf;
+
+  BFD_ASSERT (tab->sec_size == 0);
+  save_size = 1;
+  if (save != NULL)
+    save_size = save->size;
+  BFD_ASSERT (save_size <= curr_size);
+  tab->size = save_size;
+  for (idx = 1; idx < save_size; ++idx)
+    tab->array[idx]->refcount = save->refcount[idx];
+
+  for (; idx < curr_size; ++idx)
+    {
+      /* We don't remove entries from the hash table, just set their
+        REFCOUNT to zero.  Setting LEN zero will result in the size
+        growing if the entry is added again.  See _bfd_elf_strtab_add.  */
+      tab->array[idx]->refcount = 0;
+      tab->array[idx]->len = 0;
+    }
+}
+
 bfd_size_type
 _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
 {
 bfd_size_type
 _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
 {
@@ -211,7 +274,13 @@ _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
 }
 
 bfd_size_type
 }
 
 bfd_size_type
-_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
+_bfd_elf_strtab_len (struct elf_strtab_hash *tab)
+{
+  return tab->size;
+}
+
+bfd_size_type
+_bfd_elf_strtab_offset (struct elf_strtab_hash *tab, size_t idx)
 {
   struct elf_strtab_hash_entry *entry;
 
 {
   struct elf_strtab_hash_entry *entry;
 
@@ -225,13 +294,29 @@ _bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
   return tab->array[idx]->u.index;
 }
 
   return tab->array[idx]->u.index;
 }
 
-bfd_boolean
+const char *
+_bfd_elf_strtab_str (struct elf_strtab_hash *tab, size_t idx,
+                    bfd_size_type *offset)
+{
+  if (idx == 0)
+    return NULL;
+  BFD_ASSERT (idx < tab->size);
+  BFD_ASSERT (tab->sec_size);
+  if (tab->array[idx]->refcount == 0)
+    return NULL;
+  if (offset)
+    *offset = tab->array[idx]->u.index;
+  return tab->array[idx]->root.string;
+}
+
+bool
 _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
 {
 _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
 {
-  bfd_size_type off = 1, i;
+  bfd_size_type off = 1;
+  size_t i;
 
   if (bfd_bwrite ("", 1, abfd) != 1)
 
   if (bfd_bwrite ("", 1, abfd) != 1)
-    return FALSE;
+    return false;
 
   for (i = 1; i < tab->size; ++i)
     {
 
   for (i = 1; i < tab->size; ++i)
     {
@@ -245,16 +330,18 @@ _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
 
       str = tab->array[i]->root.string;
       if (bfd_bwrite (str, len, abfd) != len)
 
       str = tab->array[i]->root.string;
       if (bfd_bwrite (str, len, abfd) != len)
-       return FALSE;
+       return false;
 
       off += len;
     }
 
   BFD_ASSERT (off == tab->sec_size);
 
       off += len;
     }
 
   BFD_ASSERT (off == tab->sec_size);
-  return TRUE;
+  return true;
 }
 
 }
 
-/* Compare two elf_strtab_hash_entry structures.  Called via qsort.  */
+/* Compare two elf_strtab_hash_entry structures.  Called via qsort.
+   Won't ever return zero as all entries differ, so there is no issue
+   with qsort stability here.  */
 
 static int
 strrevcmp (const void *a, const void *b)
 
 static int
 strrevcmp (const void *a, const void *b)
@@ -263,8 +350,8 @@ strrevcmp (const void *a, const void *b)
   struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
   unsigned int lenA = A->len;
   unsigned int lenB = B->len;
   struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
   unsigned int lenA = A->len;
   unsigned int lenB = B->len;
-  const unsigned char *s = A->root.string + lenA - 1;
-  const unsigned char *t = B->root.string + lenB - 1;
+  const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
+  const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
   int l = lenA < lenB ? lenA : lenB;
 
   while (l)
   int l = lenA < lenB ? lenA : lenB;
 
   while (l)
@@ -298,17 +385,13 @@ void
 _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
 {
   struct elf_strtab_hash_entry **array, **a, *e;
 _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
 {
   struct elf_strtab_hash_entry **array, **a, *e;
-  bfd_size_type size, amt;
-
-  /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
-     a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
-     Besides, indexing with a long long wouldn't give anything but extra
-     cycles.  */
-  size_t i;
+  bfd_size_type amt, sec_size;
+  size_t size, i;
 
   /* Sort the strings by suffix and length.  */
 
   /* Sort the strings by suffix and length.  */
-  amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
-  array = bfd_malloc (amt);
+  amt = tab->size;
+  amt *= sizeof (struct elf_strtab_hash_entry *);
+  array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
   if (array == NULL)
     goto alloc_failure;
 
   if (array == NULL)
     goto alloc_failure;
 
@@ -361,23 +444,22 @@ _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
        }
     }
 
        }
     }
 
-alloc_failure:
-  if (array)
-    free (array);
+ alloc_failure:
+  free (array);
 
   /* Assign positions to the strings we want to keep.  */
 
   /* Assign positions to the strings we want to keep.  */
-  size = 1;
+  sec_size = 1;
   for (i = 1; i < tab->size; ++i)
     {
       e = tab->array[i];
       if (e->refcount && e->len > 0)
        {
   for (i = 1; i < tab->size; ++i)
     {
       e = tab->array[i];
       if (e->refcount && e->len > 0)
        {
-         e->u.index = size;
-         size += e->len;
+         e->u.index = sec_size;
+         sec_size += e->len;
        }
     }
 
        }
     }
 
-  tab->sec_size = size;
+  tab->sec_size = sec_size;
 
   /* Adjust the rest.  */
   for (i = 1; i < tab->size; ++i)
 
   /* Adjust the rest.  */
   for (i = 1; i < tab->size; ++i)