|  | /* hash.c -- hash table routines for BFD | 
|  | Copyright (C) 1993-2023 Free Software Foundation, Inc. | 
|  | Written by Steve Chamberlain <sac@cygnus.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 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program 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, write to the Free Software | 
|  | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "bfd.h" | 
|  | #include "libbfd.h" | 
|  | #include "objalloc.h" | 
|  | #include "libiberty.h" | 
|  |  | 
|  | /* | 
|  | SECTION | 
|  | Hash Tables | 
|  |  | 
|  | @cindex Hash tables | 
|  | BFD provides a simple set of hash table functions.  Routines | 
|  | are provided to initialize a hash table, to free a hash table, | 
|  | to look up a string in a hash table and optionally create an | 
|  | entry for it, and to traverse a hash table.  There is | 
|  | currently no routine to delete an string from a hash table. | 
|  |  | 
|  | The basic hash table does not permit any data to be stored | 
|  | with a string.  However, a hash table is designed to present a | 
|  | base class from which other types of hash tables may be | 
|  | derived.  These derived types may store additional information | 
|  | with the string.  Hash tables were implemented in this way, | 
|  | rather than simply providing a data pointer in a hash table | 
|  | entry, because they were designed for use by the linker back | 
|  | ends.  The linker may create thousands of hash table entries, | 
|  | and the overhead of allocating private data and storing and | 
|  | following pointers becomes noticeable. | 
|  |  | 
|  | The basic hash table code is in <<hash.c>>. | 
|  |  | 
|  | @menu | 
|  | @* Creating and Freeing a Hash Table:: | 
|  | @* Looking Up or Entering a String:: | 
|  | @* Traversing a Hash Table:: | 
|  | @* Deriving a New Hash Table Type:: | 
|  | @end menu | 
|  |  | 
|  | INODE | 
|  | Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables | 
|  | SUBSECTION | 
|  | Creating and freeing a hash table | 
|  |  | 
|  | @findex bfd_hash_table_init | 
|  | @findex bfd_hash_table_init_n | 
|  | To create a hash table, create an instance of a <<struct | 
|  | bfd_hash_table>> (defined in <<bfd.h>>) and call | 
|  | <<bfd_hash_table_init>> (if you know approximately how many | 
|  | entries you will need, the function <<bfd_hash_table_init_n>>, | 
|  | which takes a @var{size} argument, may be used). | 
|  | <<bfd_hash_table_init>> returns <<FALSE>> if some sort of | 
|  | error occurs. | 
|  |  | 
|  | @findex bfd_hash_newfunc | 
|  | The function <<bfd_hash_table_init>> take as an argument a | 
|  | function to use to create new entries.  For a basic hash | 
|  | table, use the function <<bfd_hash_newfunc>>.  @xref{Deriving | 
|  | a New Hash Table Type}, for why you would want to use a | 
|  | different value for this argument. | 
|  |  | 
|  | @findex bfd_hash_allocate | 
|  | <<bfd_hash_table_init>> will create an objalloc which will be | 
|  | used to allocate new entries.  You may allocate memory on this | 
|  | objalloc using <<bfd_hash_allocate>>. | 
|  |  | 
|  | @findex bfd_hash_table_free | 
|  | Use <<bfd_hash_table_free>> to free up all the memory that has | 
|  | been allocated for a hash table.  This will not free up the | 
|  | <<struct bfd_hash_table>> itself, which you must provide. | 
|  |  | 
|  | @findex bfd_hash_set_default_size | 
|  | Use <<bfd_hash_set_default_size>> to set the default size of | 
|  | hash table to use. | 
|  |  | 
|  | INODE | 
|  | Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables | 
|  | SUBSECTION | 
|  | Looking up or entering a string | 
|  |  | 
|  | @findex bfd_hash_lookup | 
|  | The function <<bfd_hash_lookup>> is used both to look up a | 
|  | string in the hash table and to create a new entry. | 
|  |  | 
|  | If the @var{create} argument is <<FALSE>>, <<bfd_hash_lookup>> | 
|  | will look up a string.  If the string is found, it will | 
|  | returns a pointer to a <<struct bfd_hash_entry>>.  If the | 
|  | string is not found in the table <<bfd_hash_lookup>> will | 
|  | return <<NULL>>.  You should not modify any of the fields in | 
|  | the returns <<struct bfd_hash_entry>>. | 
|  |  | 
|  | If the @var{create} argument is <<TRUE>>, the string will be | 
|  | entered into the hash table if it is not already there. | 
|  | Either way a pointer to a <<struct bfd_hash_entry>> will be | 
|  | returned, either to the existing structure or to a newly | 
|  | created one.  In this case, a <<NULL>> return means that an | 
|  | error occurred. | 
|  |  | 
|  | If the @var{create} argument is <<TRUE>>, and a new entry is | 
|  | created, the @var{copy} argument is used to decide whether to | 
|  | copy the string onto the hash table objalloc or not.  If | 
|  | @var{copy} is passed as <<FALSE>>, you must be careful not to | 
|  | deallocate or modify the string as long as the hash table | 
|  | exists. | 
|  |  | 
|  | INODE | 
|  | Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables | 
|  | SUBSECTION | 
|  | Traversing a hash table | 
|  |  | 
|  | @findex bfd_hash_traverse | 
|  | The function <<bfd_hash_traverse>> may be used to traverse a | 
|  | hash table, calling a function on each element.  The traversal | 
|  | is done in a random order. | 
|  |  | 
|  | <<bfd_hash_traverse>> takes as arguments a function and a | 
|  | generic <<void *>> pointer.  The function is called with a | 
|  | hash table entry (a <<struct bfd_hash_entry *>>) and the | 
|  | generic pointer passed to <<bfd_hash_traverse>>.  The function | 
|  | must return a <<boolean>> value, which indicates whether to | 
|  | continue traversing the hash table.  If the function returns | 
|  | <<FALSE>>, <<bfd_hash_traverse>> will stop the traversal and | 
|  | return immediately. | 
|  |  | 
|  | INODE | 
|  | Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables | 
|  | SUBSECTION | 
|  | Deriving a new hash table type | 
|  |  | 
|  | Many uses of hash tables want to store additional information | 
|  | which each entry in the hash table.  Some also find it | 
|  | convenient to store additional information with the hash table | 
|  | itself.  This may be done using a derived hash table. | 
|  |  | 
|  | Since C is not an object oriented language, creating a derived | 
|  | hash table requires sticking together some boilerplate | 
|  | routines with a few differences specific to the type of hash | 
|  | table you want to create. | 
|  |  | 
|  | An example of a derived hash table is the linker hash table. | 
|  | The structures for this are defined in <<bfdlink.h>>.  The | 
|  | functions are in <<linker.c>>. | 
|  |  | 
|  | You may also derive a hash table from an already derived hash | 
|  | table.  For example, the a.out linker backend code uses a hash | 
|  | table derived from the linker hash table. | 
|  |  | 
|  | @menu | 
|  | @* Define the Derived Structures:: | 
|  | @* Write the Derived Creation Routine:: | 
|  | @* Write Other Derived Routines:: | 
|  | @end menu | 
|  |  | 
|  | INODE | 
|  | Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type | 
|  | SUBSUBSECTION | 
|  | Define the derived structures | 
|  |  | 
|  | You must define a structure for an entry in the hash table, | 
|  | and a structure for the hash table itself. | 
|  |  | 
|  | The first field in the structure for an entry in the hash | 
|  | table must be of the type used for an entry in the hash table | 
|  | you are deriving from.  If you are deriving from a basic hash | 
|  | table this is <<struct bfd_hash_entry>>, which is defined in | 
|  | <<bfd.h>>.  The first field in the structure for the hash | 
|  | table itself must be of the type of the hash table you are | 
|  | deriving from itself.  If you are deriving from a basic hash | 
|  | table, this is <<struct bfd_hash_table>>. | 
|  |  | 
|  | For example, the linker hash table defines <<struct | 
|  | bfd_link_hash_entry>> (in <<bfdlink.h>>).  The first field, | 
|  | <<root>>, is of type <<struct bfd_hash_entry>>.  Similarly, | 
|  | the first field in <<struct bfd_link_hash_table>>, <<table>>, | 
|  | is of type <<struct bfd_hash_table>>. | 
|  |  | 
|  | INODE | 
|  | Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type | 
|  | SUBSUBSECTION | 
|  | Write the derived creation routine | 
|  |  | 
|  | You must write a routine which will create and initialize an | 
|  | entry in the hash table.  This routine is passed as the | 
|  | function argument to <<bfd_hash_table_init>>. | 
|  |  | 
|  | In order to permit other hash tables to be derived from the | 
|  | hash table you are creating, this routine must be written in a | 
|  | standard way. | 
|  |  | 
|  | The first argument to the creation routine is a pointer to a | 
|  | hash table entry.  This may be <<NULL>>, in which case the | 
|  | routine should allocate the right amount of space.  Otherwise | 
|  | the space has already been allocated by a hash table type | 
|  | derived from this one. | 
|  |  | 
|  | After allocating space, the creation routine must call the | 
|  | creation routine of the hash table type it is derived from, | 
|  | passing in a pointer to the space it just allocated.  This | 
|  | will initialize any fields used by the base hash table. | 
|  |  | 
|  | Finally the creation routine must initialize any local fields | 
|  | for the new hash table type. | 
|  |  | 
|  | Here is a boilerplate example of a creation routine. | 
|  | @var{function_name} is the name of the routine. | 
|  | @var{entry_type} is the type of an entry in the hash table you | 
|  | are creating.  @var{base_newfunc} is the name of the creation | 
|  | routine of the hash table type your hash table is derived | 
|  | from. | 
|  |  | 
|  | EXAMPLE | 
|  |  | 
|  | .struct bfd_hash_entry * | 
|  | .@var{function_name} (struct bfd_hash_entry *entry, | 
|  | .		      struct bfd_hash_table *table, | 
|  | .		      const char *string) | 
|  | .{ | 
|  | .  struct @var{entry_type} *ret = (@var{entry_type} *) entry; | 
|  | . | 
|  | . {* Allocate the structure if it has not already been allocated by a | 
|  | .    derived class.  *} | 
|  | .  if (ret == NULL) | 
|  | .    { | 
|  | .      ret = bfd_hash_allocate (table, sizeof (* ret)); | 
|  | .      if (ret == NULL) | 
|  | .	 return NULL; | 
|  | .    } | 
|  | . | 
|  | . {* Call the allocation method of the base class.  *} | 
|  | .  ret = ((@var{entry_type} *) | 
|  | .	  @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string)); | 
|  | . | 
|  | . {* Initialize the local fields here.  *} | 
|  | . | 
|  | .  return (struct bfd_hash_entry *) ret; | 
|  | .} | 
|  |  | 
|  | DESCRIPTION | 
|  | The creation routine for the linker hash table, which is in | 
|  | <<linker.c>>, looks just like this example. | 
|  | @var{function_name} is <<_bfd_link_hash_newfunc>>. | 
|  | @var{entry_type} is <<struct bfd_link_hash_entry>>. | 
|  | @var{base_newfunc} is <<bfd_hash_newfunc>>, the creation | 
|  | routine for a basic hash table. | 
|  |  | 
|  | <<_bfd_link_hash_newfunc>> also initializes the local fields | 
|  | in a linker hash table entry: <<type>>, <<written>> and | 
|  | <<next>>. | 
|  |  | 
|  | INODE | 
|  | Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type | 
|  | SUBSUBSECTION | 
|  | Write other derived routines | 
|  |  | 
|  | You will want to write other routines for your new hash table, | 
|  | as well. | 
|  |  | 
|  | You will want an initialization routine which calls the | 
|  | initialization routine of the hash table you are deriving from | 
|  | and initializes any other local fields.  For the linker hash | 
|  | table, this is <<_bfd_link_hash_table_init>> in <<linker.c>>. | 
|  |  | 
|  | You will want a lookup routine which calls the lookup routine | 
|  | of the hash table you are deriving from and casts the result. | 
|  | The linker hash table uses <<bfd_link_hash_lookup>> in | 
|  | <<linker.c>> (this actually takes an additional argument which | 
|  | it uses to decide how to return the looked up value). | 
|  |  | 
|  | You may want a traversal routine.  This should just call the | 
|  | traversal routine of the hash table you are deriving from with | 
|  | appropriate casts.  The linker hash table uses | 
|  | <<bfd_link_hash_traverse>> in <<linker.c>>. | 
|  |  | 
|  | These routines may simply be defined as macros.  For example, | 
|  | the a.out backend linker hash table, which is derived from the | 
|  | linker hash table, uses macros for the lookup and traversal | 
|  | routines.  These are <<aout_link_hash_lookup>> and | 
|  | <<aout_link_hash_traverse>> in aoutx.h. | 
|  |  | 
|  | EXTERNAL | 
|  | .{* An element in the hash table.  Most uses will actually use a larger | 
|  | .   structure, and an instance of this will be the first field.  *} | 
|  | . | 
|  | .struct bfd_hash_entry | 
|  | .{ | 
|  | .  {* Next entry for this hash code.  *} | 
|  | .  struct bfd_hash_entry *next; | 
|  | .  {* String being hashed.  *} | 
|  | .  const char *string; | 
|  | .  {* Hash code.  This is the full hash code, not the index into the | 
|  | .     table.  *} | 
|  | .  unsigned long hash; | 
|  | .}; | 
|  | . | 
|  | .{* A hash table.  *} | 
|  | . | 
|  | .struct bfd_hash_table | 
|  | .{ | 
|  | .  {* The hash array.  *} | 
|  | .  struct bfd_hash_entry **table; | 
|  | .  {* A function used to create new elements in the hash table.  The | 
|  | .     first entry is itself a pointer to an element.  When this | 
|  | .     function is first invoked, this pointer will be NULL.  However, | 
|  | .     having the pointer permits a hierarchy of method functions to be | 
|  | .     built each of which calls the function in the superclass.  Thus | 
|  | .     each function should be written to allocate a new block of memory | 
|  | .     only if the argument is NULL.  *} | 
|  | .  struct bfd_hash_entry *(*newfunc) | 
|  | .    (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); | 
|  | .  {* An objalloc for this hash table.  This is a struct objalloc *, | 
|  | .     but we use void * to avoid requiring the inclusion of objalloc.h.  *} | 
|  | .  void *memory; | 
|  | .  {* The number of slots in the hash table.  *} | 
|  | .  unsigned int size; | 
|  | .  {* The number of entries in the hash table.  *} | 
|  | .  unsigned int count; | 
|  | .  {* The size of elements.  *} | 
|  | .  unsigned int entsize; | 
|  | .  {* If non-zero, don't grow the hash table.  *} | 
|  | .  unsigned int frozen:1; | 
|  | .}; | 
|  | . | 
|  | */ | 
|  |  | 
|  | /* The default number of entries to use when creating a hash table.  */ | 
|  | #define DEFAULT_SIZE 4051 | 
|  |  | 
|  | /* The following function returns a nearest prime number which is | 
|  | greater than N, and near a power of two.  Copied from libiberty. | 
|  | Returns zero for ridiculously large N to signify an error.  */ | 
|  |  | 
|  | static uint32_t | 
|  | higher_prime_number (uint32_t n) | 
|  | { | 
|  | /* These are primes that are near, but slightly smaller than, a | 
|  | power of two.  */ | 
|  | static const uint32_t primes[] = | 
|  | { | 
|  | UINT32_C (31), | 
|  | UINT32_C (61), | 
|  | UINT32_C (127), | 
|  | UINT32_C (251), | 
|  | UINT32_C (509), | 
|  | UINT32_C (1021), | 
|  | UINT32_C (2039), | 
|  | UINT32_C (4093), | 
|  | UINT32_C (8191), | 
|  | UINT32_C (16381), | 
|  | UINT32_C (32749), | 
|  | UINT32_C (65521), | 
|  | UINT32_C (131071), | 
|  | UINT32_C (262139), | 
|  | UINT32_C (524287), | 
|  | UINT32_C (1048573), | 
|  | UINT32_C (2097143), | 
|  | UINT32_C (4194301), | 
|  | UINT32_C (8388593), | 
|  | UINT32_C (16777213), | 
|  | UINT32_C (33554393), | 
|  | UINT32_C (67108859), | 
|  | UINT32_C (134217689), | 
|  | UINT32_C (268435399), | 
|  | UINT32_C (536870909), | 
|  | UINT32_C (1073741789), | 
|  | UINT32_C (2147483647), | 
|  | UINT32_C (4294967291) | 
|  | }; | 
|  |  | 
|  | const uint32_t *low = &primes[0]; | 
|  | const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])]; | 
|  |  | 
|  | while (low != high) | 
|  | { | 
|  | const uint32_t *mid = low + (high - low) / 2; | 
|  | if (n >= *mid) | 
|  | low = mid + 1; | 
|  | else | 
|  | high = mid; | 
|  | } | 
|  |  | 
|  | if (n >= *low) | 
|  | return 0; | 
|  |  | 
|  | return *low; | 
|  | } | 
|  |  | 
|  | static unsigned int bfd_default_hash_table_size = DEFAULT_SIZE; | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_table_init_n | 
|  |  | 
|  | SYNOPSIS | 
|  | bool bfd_hash_table_init_n | 
|  | (struct bfd_hash_table *, | 
|  | struct bfd_hash_entry *(* {*newfunc*}) | 
|  | (struct bfd_hash_entry *, struct bfd_hash_table *, const char *), | 
|  | unsigned int {*entsize*}, unsigned int {*size*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Create a new hash table, given a number of entries. | 
|  | */ | 
|  |  | 
|  | bool | 
|  | bfd_hash_table_init_n (struct bfd_hash_table *table, | 
|  | struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, | 
|  | struct bfd_hash_table *, | 
|  | const char *), | 
|  | unsigned int entsize, | 
|  | unsigned int size) | 
|  | { | 
|  | unsigned long alloc; | 
|  |  | 
|  | alloc = size; | 
|  | alloc *= sizeof (struct bfd_hash_entry *); | 
|  | if (alloc / sizeof (struct bfd_hash_entry *) != size) | 
|  | { | 
|  | bfd_set_error (bfd_error_no_memory); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | table->memory = (void *) objalloc_create (); | 
|  | if (table->memory == NULL) | 
|  | { | 
|  | bfd_set_error (bfd_error_no_memory); | 
|  | return false; | 
|  | } | 
|  | table->table = (struct bfd_hash_entry **) | 
|  | objalloc_alloc ((struct objalloc *) table->memory, alloc); | 
|  | if (table->table == NULL) | 
|  | { | 
|  | bfd_hash_table_free (table); | 
|  | bfd_set_error (bfd_error_no_memory); | 
|  | return false; | 
|  | } | 
|  | memset ((void *) table->table, 0, alloc); | 
|  | table->size = size; | 
|  | table->entsize = entsize; | 
|  | table->count = 0; | 
|  | table->frozen = 0; | 
|  | table->newfunc = newfunc; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_table_init | 
|  |  | 
|  | SYNOPSIS | 
|  | bool bfd_hash_table_init | 
|  | (struct bfd_hash_table *, | 
|  | struct bfd_hash_entry *(* {*newfunc*}) | 
|  | (struct bfd_hash_entry *, struct bfd_hash_table *, const char *), | 
|  | unsigned int {*entsize*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Create a new hash table with the default number of entries. | 
|  | */ | 
|  |  | 
|  | bool | 
|  | bfd_hash_table_init (struct bfd_hash_table *table, | 
|  | struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, | 
|  | struct bfd_hash_table *, | 
|  | const char *), | 
|  | unsigned int entsize) | 
|  | { | 
|  | return bfd_hash_table_init_n (table, newfunc, entsize, | 
|  | bfd_default_hash_table_size); | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_table_free | 
|  |  | 
|  | SYNOPSIS | 
|  | void bfd_hash_table_free (struct bfd_hash_table *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Free a hash table. | 
|  | */ | 
|  |  | 
|  | void | 
|  | bfd_hash_table_free (struct bfd_hash_table *table) | 
|  | { | 
|  | objalloc_free ((struct objalloc *) table->memory); | 
|  | table->memory = NULL; | 
|  | } | 
|  |  | 
|  | static inline unsigned long | 
|  | bfd_hash_hash (const char *string, unsigned int *lenp) | 
|  | { | 
|  | const unsigned char *s; | 
|  | unsigned long hash; | 
|  | unsigned int len; | 
|  | unsigned int c; | 
|  |  | 
|  | BFD_ASSERT (string != NULL); | 
|  | hash = 0; | 
|  | len = 0; | 
|  | s = (const unsigned char *) string; | 
|  | while ((c = *s++) != '\0') | 
|  | { | 
|  | hash += c + (c << 17); | 
|  | hash ^= hash >> 2; | 
|  | } | 
|  | len = (s - (const unsigned char *) string) - 1; | 
|  | hash += len + (len << 17); | 
|  | hash ^= hash >> 2; | 
|  | if (lenp != NULL) | 
|  | *lenp = len; | 
|  | return hash; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_lookup | 
|  |  | 
|  | SYNOPSIS | 
|  | struct bfd_hash_entry *bfd_hash_lookup | 
|  | (struct bfd_hash_table *, const char *, | 
|  | bool {*create*}, bool {*copy*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Look up a string in a hash table. | 
|  | */ | 
|  |  | 
|  | struct bfd_hash_entry * | 
|  | bfd_hash_lookup (struct bfd_hash_table *table, | 
|  | const char *string, | 
|  | bool create, | 
|  | bool copy) | 
|  | { | 
|  | unsigned long hash; | 
|  | struct bfd_hash_entry *hashp; | 
|  | unsigned int len; | 
|  | unsigned int _index; | 
|  |  | 
|  | hash = bfd_hash_hash (string, &len); | 
|  | _index = hash % table->size; | 
|  | for (hashp = table->table[_index]; | 
|  | hashp != NULL; | 
|  | hashp = hashp->next) | 
|  | { | 
|  | if (hashp->hash == hash | 
|  | && strcmp (hashp->string, string) == 0) | 
|  | return hashp; | 
|  | } | 
|  |  | 
|  | if (! create) | 
|  | return NULL; | 
|  |  | 
|  | if (copy) | 
|  | { | 
|  | char *new_string; | 
|  |  | 
|  | new_string = (char *) objalloc_alloc ((struct objalloc *) table->memory, | 
|  | len + 1); | 
|  | if (!new_string) | 
|  | { | 
|  | bfd_set_error (bfd_error_no_memory); | 
|  | return NULL; | 
|  | } | 
|  | memcpy (new_string, string, len + 1); | 
|  | string = new_string; | 
|  | } | 
|  |  | 
|  | return bfd_hash_insert (table, string, hash); | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_insert | 
|  |  | 
|  | SYNOPSIS | 
|  | struct bfd_hash_entry *bfd_hash_insert | 
|  | (struct bfd_hash_table *, | 
|  | const char *, | 
|  | unsigned long {*hash*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Insert an entry in a hash table. | 
|  | */ | 
|  |  | 
|  | struct bfd_hash_entry * | 
|  | bfd_hash_insert (struct bfd_hash_table *table, | 
|  | const char *string, | 
|  | unsigned long hash) | 
|  | { | 
|  | struct bfd_hash_entry *hashp; | 
|  | unsigned int _index; | 
|  |  | 
|  | hashp = (*table->newfunc) (NULL, table, string); | 
|  | if (hashp == NULL) | 
|  | return NULL; | 
|  | hashp->string = string; | 
|  | hashp->hash = hash; | 
|  | _index = hash % table->size; | 
|  | hashp->next = table->table[_index]; | 
|  | table->table[_index] = hashp; | 
|  | table->count++; | 
|  |  | 
|  | if (!table->frozen && table->count > table->size * 3 / 4) | 
|  | { | 
|  | unsigned long newsize = higher_prime_number (table->size); | 
|  | struct bfd_hash_entry **newtable; | 
|  | unsigned int hi; | 
|  | unsigned long alloc = newsize * sizeof (struct bfd_hash_entry *); | 
|  |  | 
|  | /* If we can't find a higher prime, or we can't possibly alloc | 
|  | that much memory, don't try to grow the table.  */ | 
|  | if (newsize == 0 || alloc / sizeof (struct bfd_hash_entry *) != newsize) | 
|  | { | 
|  | table->frozen = 1; | 
|  | return hashp; | 
|  | } | 
|  |  | 
|  | newtable = ((struct bfd_hash_entry **) | 
|  | objalloc_alloc ((struct objalloc *) table->memory, alloc)); | 
|  | if (newtable == NULL) | 
|  | { | 
|  | table->frozen = 1; | 
|  | return hashp; | 
|  | } | 
|  | memset (newtable, 0, alloc); | 
|  |  | 
|  | for (hi = 0; hi < table->size; hi ++) | 
|  | while (table->table[hi]) | 
|  | { | 
|  | struct bfd_hash_entry *chain = table->table[hi]; | 
|  | struct bfd_hash_entry *chain_end = chain; | 
|  |  | 
|  | while (chain_end->next && chain_end->next->hash == chain->hash) | 
|  | chain_end = chain_end->next; | 
|  |  | 
|  | table->table[hi] = chain_end->next; | 
|  | _index = chain->hash % newsize; | 
|  | chain_end->next = newtable[_index]; | 
|  | newtable[_index] = chain; | 
|  | } | 
|  | table->table = newtable; | 
|  | table->size = newsize; | 
|  | } | 
|  |  | 
|  | return hashp; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_rename | 
|  |  | 
|  | SYNOPSIS | 
|  | void bfd_hash_rename (struct bfd_hash_table *, | 
|  | const char *, | 
|  | struct bfd_hash_entry *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Rename an entry in a hash table. | 
|  | */ | 
|  |  | 
|  | void | 
|  | bfd_hash_rename (struct bfd_hash_table *table, | 
|  | const char *string, | 
|  | struct bfd_hash_entry *ent) | 
|  | { | 
|  | unsigned int _index; | 
|  | struct bfd_hash_entry **pph; | 
|  |  | 
|  | _index = ent->hash % table->size; | 
|  | for (pph = &table->table[_index]; *pph != NULL; pph = &(*pph)->next) | 
|  | if (*pph == ent) | 
|  | break; | 
|  | if (*pph == NULL) | 
|  | abort (); | 
|  |  | 
|  | *pph = ent->next; | 
|  | ent->string = string; | 
|  | ent->hash = bfd_hash_hash (string, NULL); | 
|  | _index = ent->hash % table->size; | 
|  | ent->next = table->table[_index]; | 
|  | table->table[_index] = ent; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_replace | 
|  |  | 
|  | SYNOPSIS | 
|  | void bfd_hash_replace (struct bfd_hash_table *, | 
|  | struct bfd_hash_entry * {*old*}, | 
|  | struct bfd_hash_entry * {*new*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Replace an entry in a hash table. | 
|  | */ | 
|  |  | 
|  | void | 
|  | bfd_hash_replace (struct bfd_hash_table *table, | 
|  | struct bfd_hash_entry *old, | 
|  | struct bfd_hash_entry *nw) | 
|  | { | 
|  | unsigned int _index; | 
|  | struct bfd_hash_entry **pph; | 
|  |  | 
|  | _index = old->hash % table->size; | 
|  | for (pph = &table->table[_index]; | 
|  | (*pph) != NULL; | 
|  | pph = &(*pph)->next) | 
|  | { | 
|  | if (*pph == old) | 
|  | { | 
|  | *pph = nw; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | abort (); | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_allocate | 
|  |  | 
|  | SYNOPSIS | 
|  | void *bfd_hash_allocate (struct bfd_hash_table *, | 
|  | unsigned int {*size*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Allocate space in a hash table. | 
|  | */ | 
|  |  | 
|  | void * | 
|  | bfd_hash_allocate (struct bfd_hash_table *table, | 
|  | unsigned int size) | 
|  | { | 
|  | void * ret; | 
|  |  | 
|  | ret = objalloc_alloc ((struct objalloc *) table->memory, size); | 
|  | if (ret == NULL && size != 0) | 
|  | bfd_set_error (bfd_error_no_memory); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_newfunc | 
|  |  | 
|  | SYNOPSIS | 
|  | struct bfd_hash_entry *bfd_hash_newfunc | 
|  | (struct bfd_hash_entry *, | 
|  | struct bfd_hash_table *, | 
|  | const char *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Base method for creating a new hash table entry. | 
|  | */ | 
|  |  | 
|  | struct bfd_hash_entry * | 
|  | bfd_hash_newfunc (struct bfd_hash_entry *entry, | 
|  | struct bfd_hash_table *table, | 
|  | const char *string ATTRIBUTE_UNUSED) | 
|  | { | 
|  | if (entry == NULL) | 
|  | entry = (struct bfd_hash_entry *) bfd_hash_allocate (table, | 
|  | sizeof (* entry)); | 
|  | return entry; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_traverse | 
|  |  | 
|  | SYNOPSIS | 
|  | void bfd_hash_traverse | 
|  | (struct bfd_hash_table *, | 
|  | bool (*) (struct bfd_hash_entry *, void *), | 
|  | void *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Traverse a hash table. | 
|  | */ | 
|  |  | 
|  | void | 
|  | bfd_hash_traverse (struct bfd_hash_table *table, | 
|  | bool (*func) (struct bfd_hash_entry *, void *), | 
|  | void *info) | 
|  | { | 
|  | unsigned int i; | 
|  |  | 
|  | table->frozen = 1; | 
|  | for (i = 0; i < table->size; i++) | 
|  | { | 
|  | struct bfd_hash_entry *p; | 
|  |  | 
|  | for (p = table->table[i]; p != NULL; p = p->next) | 
|  | if (! (*func) (p, info)) | 
|  | goto out; | 
|  | } | 
|  | out: | 
|  | table->frozen = 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | FUNCTION | 
|  | bfd_hash_set_default_size | 
|  |  | 
|  | SYNOPSIS | 
|  | unsigned int bfd_hash_set_default_size (unsigned int); | 
|  |  | 
|  | DESCRIPTION | 
|  | Set hash table default size. | 
|  | */ | 
|  |  | 
|  | unsigned int | 
|  | bfd_hash_set_default_size (unsigned int hash_size) | 
|  | { | 
|  | /* These silly_size values result in around 1G and 32M of memory | 
|  | being allocated for the table of pointers.  Note that the number | 
|  | of elements allocated will be almost twice the size of any power | 
|  | of two chosen here.  */ | 
|  | unsigned int silly_size = sizeof (size_t) > 4 ? 0x4000000 : 0x400000; | 
|  | if (hash_size > silly_size) | 
|  | hash_size = silly_size; | 
|  | else if (hash_size != 0) | 
|  | hash_size--; | 
|  | hash_size = higher_prime_number (hash_size); | 
|  | BFD_ASSERT (hash_size != 0); | 
|  | bfd_default_hash_table_size = hash_size; | 
|  | return bfd_default_hash_table_size; | 
|  | } | 
|  |  | 
|  | /* A few different object file formats (a.out, COFF, ELF) use a string | 
|  | table.  These functions support adding strings to a string table, | 
|  | returning the byte offset, and writing out the table. | 
|  |  | 
|  | Possible improvements: | 
|  | + look for strings matching trailing substrings of other strings | 
|  | + better data structures?  balanced trees? | 
|  | + look at reducing memory use elsewhere -- maybe if we didn't have | 
|  | to construct the entire symbol table at once, we could get by | 
|  | with smaller amounts of VM?  (What effect does that have on the | 
|  | string table reductions?)  */ | 
|  |  | 
|  | /* An entry in the strtab hash table.  */ | 
|  |  | 
|  | struct strtab_hash_entry | 
|  | { | 
|  | struct bfd_hash_entry root; | 
|  | /* Index in string table.  */ | 
|  | bfd_size_type index; | 
|  | /* Next string in strtab.  */ | 
|  | struct strtab_hash_entry *next; | 
|  | }; | 
|  |  | 
|  | /* The strtab hash table.  */ | 
|  |  | 
|  | struct bfd_strtab_hash | 
|  | { | 
|  | struct bfd_hash_table table; | 
|  | /* Size of strtab--also next available index.  */ | 
|  | bfd_size_type size; | 
|  | /* First string in strtab.  */ | 
|  | struct strtab_hash_entry *first; | 
|  | /* Last string in strtab.  */ | 
|  | struct strtab_hash_entry *last; | 
|  | /* Whether to precede strings with a two or four byte length, | 
|  | as in the XCOFF .debug section.  */ | 
|  | char length_field_size; | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* Routine to create an entry in a strtab.  */ | 
|  |  | 
|  | static struct bfd_hash_entry * | 
|  | strtab_hash_newfunc (struct bfd_hash_entry *entry, | 
|  | struct bfd_hash_table *table, | 
|  | const char *string) | 
|  | { | 
|  | struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry; | 
|  |  | 
|  | /* Allocate the structure if it has not already been allocated by a | 
|  | subclass.  */ | 
|  | if (ret == NULL) | 
|  | ret = (struct strtab_hash_entry *) bfd_hash_allocate (table, | 
|  | sizeof (* ret)); | 
|  | if (ret == NULL) | 
|  | return NULL; | 
|  |  | 
|  | /* Call the allocation method of the superclass.  */ | 
|  | ret = (struct strtab_hash_entry *) | 
|  | bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string); | 
|  |  | 
|  | if (ret) | 
|  | { | 
|  | /* Initialize the local fields.  */ | 
|  | ret->index = (bfd_size_type) -1; | 
|  | ret->next = NULL; | 
|  | } | 
|  |  | 
|  | return (struct bfd_hash_entry *) ret; | 
|  | } | 
|  |  | 
|  | /* Look up an entry in an strtab.  */ | 
|  |  | 
|  | #define strtab_hash_lookup(t, string, create, copy) \ | 
|  | ((struct strtab_hash_entry *) \ | 
|  | bfd_hash_lookup (&(t)->table, (string), (create), (copy))) | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_stringtab_init | 
|  |  | 
|  | SYNOPSIS | 
|  | struct bfd_strtab_hash *_bfd_stringtab_init (void); | 
|  |  | 
|  | DESCRIPTION | 
|  | Create a new strtab. | 
|  | */ | 
|  |  | 
|  | struct bfd_strtab_hash * | 
|  | _bfd_stringtab_init (void) | 
|  | { | 
|  | struct bfd_strtab_hash *table; | 
|  | size_t amt = sizeof (* table); | 
|  |  | 
|  | table = (struct bfd_strtab_hash *) bfd_malloc (amt); | 
|  | if (table == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (!bfd_hash_table_init (&table->table, strtab_hash_newfunc, | 
|  | sizeof (struct strtab_hash_entry))) | 
|  | { | 
|  | free (table); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | table->size = 0; | 
|  | table->first = NULL; | 
|  | table->last = NULL; | 
|  | table->length_field_size = 0; | 
|  |  | 
|  | return table; | 
|  | } | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_xcoff_stringtab_init | 
|  |  | 
|  | SYNOPSIS | 
|  | struct bfd_strtab_hash *_bfd_xcoff_stringtab_init | 
|  | (bool {*isxcoff64*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Create a new strtab in which the strings are output in the format | 
|  | used in the XCOFF .debug section: a two byte length precedes each | 
|  | string. | 
|  | */ | 
|  |  | 
|  | struct bfd_strtab_hash * | 
|  | _bfd_xcoff_stringtab_init (bool isxcoff64) | 
|  | { | 
|  | struct bfd_strtab_hash *ret; | 
|  |  | 
|  | ret = _bfd_stringtab_init (); | 
|  | if (ret != NULL) | 
|  | ret->length_field_size = isxcoff64 ? 4 : 2; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_stringtab_free | 
|  |  | 
|  | SYNOPSIS | 
|  | void _bfd_stringtab_free (struct bfd_strtab_hash *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Free a strtab. | 
|  | */ | 
|  |  | 
|  | void | 
|  | _bfd_stringtab_free (struct bfd_strtab_hash *table) | 
|  | { | 
|  | bfd_hash_table_free (&table->table); | 
|  | free (table); | 
|  | } | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_stringtab_add | 
|  |  | 
|  | SYNOPSIS | 
|  | bfd_size_type _bfd_stringtab_add | 
|  | (struct bfd_strtab_hash *, const char *, | 
|  | bool {*hash*}, bool {*copy*}); | 
|  |  | 
|  | DESCRIPTION | 
|  | Get the index of a string in a strtab, adding it if it is not | 
|  | already present.  If HASH is FALSE, we don't really use the hash | 
|  | table, and we don't eliminate duplicate strings.  If COPY is true | 
|  | then store a copy of STR if creating a new entry. | 
|  | */ | 
|  |  | 
|  | bfd_size_type | 
|  | _bfd_stringtab_add (struct bfd_strtab_hash *tab, | 
|  | const char *str, | 
|  | bool hash, | 
|  | bool copy) | 
|  | { | 
|  | struct strtab_hash_entry *entry; | 
|  |  | 
|  | if (hash) | 
|  | { | 
|  | entry = strtab_hash_lookup (tab, str, true, copy); | 
|  | if (entry == NULL) | 
|  | return (bfd_size_type) -1; | 
|  | } | 
|  | else | 
|  | { | 
|  | entry = (struct strtab_hash_entry *) bfd_hash_allocate (&tab->table, | 
|  | sizeof (* entry)); | 
|  | if (entry == NULL) | 
|  | return (bfd_size_type) -1; | 
|  | if (! copy) | 
|  | entry->root.string = str; | 
|  | else | 
|  | { | 
|  | size_t len = strlen (str) + 1; | 
|  | char *n; | 
|  |  | 
|  | n = (char *) bfd_hash_allocate (&tab->table, len); | 
|  | if (n == NULL) | 
|  | return (bfd_size_type) -1; | 
|  | memcpy (n, str, len); | 
|  | entry->root.string = n; | 
|  | } | 
|  | entry->index = (bfd_size_type) -1; | 
|  | entry->next = NULL; | 
|  | } | 
|  |  | 
|  | if (entry->index == (bfd_size_type) -1) | 
|  | { | 
|  | entry->index = tab->size; | 
|  | tab->size += strlen (str) + 1; | 
|  | entry->index += tab->length_field_size; | 
|  | tab->size += tab->length_field_size; | 
|  | if (tab->first == NULL) | 
|  | tab->first = entry; | 
|  | else | 
|  | tab->last->next = entry; | 
|  | tab->last = entry; | 
|  | } | 
|  |  | 
|  | return entry->index; | 
|  | } | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_stringtab_size | 
|  |  | 
|  | SYNOPSIS | 
|  | bfd_size_type _bfd_stringtab_size (struct bfd_strtab_hash *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Get the number of bytes in a strtab. | 
|  | */ | 
|  |  | 
|  | bfd_size_type | 
|  | _bfd_stringtab_size (struct bfd_strtab_hash *tab) | 
|  | { | 
|  | return tab->size; | 
|  | } | 
|  |  | 
|  | /* | 
|  | INTERNAL_FUNCTION | 
|  | _bfd_stringtab_emit | 
|  |  | 
|  | SYNOPSIS | 
|  | bool _bfd_stringtab_emit (bfd *, struct bfd_strtab_hash *); | 
|  |  | 
|  | DESCRIPTION | 
|  | Write out a strtab.  ABFD must already be at the right location in | 
|  | the file. | 
|  | */ | 
|  |  | 
|  | bool | 
|  | _bfd_stringtab_emit (bfd *abfd, struct bfd_strtab_hash *tab) | 
|  | { | 
|  | struct strtab_hash_entry *entry; | 
|  |  | 
|  | for (entry = tab->first; entry != NULL; entry = entry->next) | 
|  | { | 
|  | const char *str; | 
|  | size_t len; | 
|  |  | 
|  | str = entry->root.string; | 
|  | len = strlen (str) + 1; | 
|  |  | 
|  | if (tab->length_field_size == 4) | 
|  | { | 
|  | bfd_byte buf[4]; | 
|  |  | 
|  | /* The output length includes the null byte.  */ | 
|  | bfd_put_32 (abfd, len, buf); | 
|  | if (bfd_write (buf, 4, abfd) != 4) | 
|  | return false; | 
|  | } | 
|  | else if (tab->length_field_size == 2) | 
|  | { | 
|  | bfd_byte buf[2]; | 
|  |  | 
|  | /* The output length includes the null byte.  */ | 
|  | bfd_put_16 (abfd, len, buf); | 
|  | if (bfd_write (buf, 2, abfd) != 2) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (bfd_write (str, len, abfd) != len) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } |