1 | /* hash.c -- hash table routines for BFD
|
---|
2 | Copyright 1993, 1994, 1995, 1997, 1999, 2001
|
---|
3 | Free Software Foundation, Inc.
|
---|
4 | Written by Steve Chamberlain <sac@cygnus.com>
|
---|
5 |
|
---|
6 | This file is part of BFD, the Binary File Descriptor library.
|
---|
7 |
|
---|
8 | This program is free software; you can redistribute it and/or modify
|
---|
9 | it under the terms of the GNU General Public License as published by
|
---|
10 | the Free Software Foundation; either version 2 of the License, or
|
---|
11 | (at your option) any later version.
|
---|
12 |
|
---|
13 | This program is distributed in the hope that it will be useful,
|
---|
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | GNU General Public License for more details.
|
---|
17 |
|
---|
18 | You should have received a copy of the GNU General Public License
|
---|
19 | along with this program; if not, write to the Free Software
|
---|
20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
---|
21 |
|
---|
22 | #include "bfd.h"
|
---|
23 | #include "sysdep.h"
|
---|
24 | #include "libbfd.h"
|
---|
25 | #include "objalloc.h"
|
---|
26 |
|
---|
27 | /*
|
---|
28 | SECTION
|
---|
29 | Hash Tables
|
---|
30 |
|
---|
31 | @cindex Hash tables
|
---|
32 | BFD provides a simple set of hash table functions. Routines
|
---|
33 | are provided to initialize a hash table, to free a hash table,
|
---|
34 | to look up a string in a hash table and optionally create an
|
---|
35 | entry for it, and to traverse a hash table. There is
|
---|
36 | currently no routine to delete an string from a hash table.
|
---|
37 |
|
---|
38 | The basic hash table does not permit any data to be stored
|
---|
39 | with a string. However, a hash table is designed to present a
|
---|
40 | base class from which other types of hash tables may be
|
---|
41 | derived. These derived types may store additional information
|
---|
42 | with the string. Hash tables were implemented in this way,
|
---|
43 | rather than simply providing a data pointer in a hash table
|
---|
44 | entry, because they were designed for use by the linker back
|
---|
45 | ends. The linker may create thousands of hash table entries,
|
---|
46 | and the overhead of allocating private data and storing and
|
---|
47 | following pointers becomes noticeable.
|
---|
48 |
|
---|
49 | The basic hash table code is in <<hash.c>>.
|
---|
50 |
|
---|
51 | @menu
|
---|
52 | @* Creating and Freeing a Hash Table::
|
---|
53 | @* Looking Up or Entering a String::
|
---|
54 | @* Traversing a Hash Table::
|
---|
55 | @* Deriving a New Hash Table Type::
|
---|
56 | @end menu
|
---|
57 |
|
---|
58 | INODE
|
---|
59 | Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables
|
---|
60 | SUBSECTION
|
---|
61 | Creating and freeing a hash table
|
---|
62 |
|
---|
63 | @findex bfd_hash_table_init
|
---|
64 | @findex bfd_hash_table_init_n
|
---|
65 | To create a hash table, create an instance of a <<struct
|
---|
66 | bfd_hash_table>> (defined in <<bfd.h>>) and call
|
---|
67 | <<bfd_hash_table_init>> (if you know approximately how many
|
---|
68 | entries you will need, the function <<bfd_hash_table_init_n>>,
|
---|
69 | which takes a @var{size} argument, may be used).
|
---|
70 | <<bfd_hash_table_init>> returns <<false>> if some sort of
|
---|
71 | error occurs.
|
---|
72 |
|
---|
73 | @findex bfd_hash_newfunc
|
---|
74 | The function <<bfd_hash_table_init>> take as an argument a
|
---|
75 | function to use to create new entries. For a basic hash
|
---|
76 | table, use the function <<bfd_hash_newfunc>>. @xref{Deriving
|
---|
77 | a New Hash Table Type}, for why you would want to use a
|
---|
78 | different value for this argument.
|
---|
79 |
|
---|
80 | @findex bfd_hash_allocate
|
---|
81 | <<bfd_hash_table_init>> will create an objalloc which will be
|
---|
82 | used to allocate new entries. You may allocate memory on this
|
---|
83 | objalloc using <<bfd_hash_allocate>>.
|
---|
84 |
|
---|
85 | @findex bfd_hash_table_free
|
---|
86 | Use <<bfd_hash_table_free>> to free up all the memory that has
|
---|
87 | been allocated for a hash table. This will not free up the
|
---|
88 | <<struct bfd_hash_table>> itself, which you must provide.
|
---|
89 |
|
---|
90 | INODE
|
---|
91 | Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables
|
---|
92 | SUBSECTION
|
---|
93 | Looking up or entering a string
|
---|
94 |
|
---|
95 | @findex bfd_hash_lookup
|
---|
96 | The function <<bfd_hash_lookup>> is used both to look up a
|
---|
97 | string in the hash table and to create a new entry.
|
---|
98 |
|
---|
99 | If the @var{create} argument is <<false>>, <<bfd_hash_lookup>>
|
---|
100 | will look up a string. If the string is found, it will
|
---|
101 | returns a pointer to a <<struct bfd_hash_entry>>. If the
|
---|
102 | string is not found in the table <<bfd_hash_lookup>> will
|
---|
103 | return <<NULL>>. You should not modify any of the fields in
|
---|
104 | the returns <<struct bfd_hash_entry>>.
|
---|
105 |
|
---|
106 | If the @var{create} argument is <<true>>, the string will be
|
---|
107 | entered into the hash table if it is not already there.
|
---|
108 | Either way a pointer to a <<struct bfd_hash_entry>> will be
|
---|
109 | returned, either to the existing structure or to a newly
|
---|
110 | created one. In this case, a <<NULL>> return means that an
|
---|
111 | error occurred.
|
---|
112 |
|
---|
113 | If the @var{create} argument is <<true>>, and a new entry is
|
---|
114 | created, the @var{copy} argument is used to decide whether to
|
---|
115 | copy the string onto the hash table objalloc or not. If
|
---|
116 | @var{copy} is passed as <<false>>, you must be careful not to
|
---|
117 | deallocate or modify the string as long as the hash table
|
---|
118 | exists.
|
---|
119 |
|
---|
120 | INODE
|
---|
121 | Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables
|
---|
122 | SUBSECTION
|
---|
123 | Traversing a hash table
|
---|
124 |
|
---|
125 | @findex bfd_hash_traverse
|
---|
126 | The function <<bfd_hash_traverse>> may be used to traverse a
|
---|
127 | hash table, calling a function on each element. The traversal
|
---|
128 | is done in a random order.
|
---|
129 |
|
---|
130 | <<bfd_hash_traverse>> takes as arguments a function and a
|
---|
131 | generic <<void *>> pointer. The function is called with a
|
---|
132 | hash table entry (a <<struct bfd_hash_entry *>>) and the
|
---|
133 | generic pointer passed to <<bfd_hash_traverse>>. The function
|
---|
134 | must return a <<boolean>> value, which indicates whether to
|
---|
135 | continue traversing the hash table. If the function returns
|
---|
136 | <<false>>, <<bfd_hash_traverse>> will stop the traversal and
|
---|
137 | return immediately.
|
---|
138 |
|
---|
139 | INODE
|
---|
140 | Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables
|
---|
141 | SUBSECTION
|
---|
142 | Deriving a new hash table type
|
---|
143 |
|
---|
144 | Many uses of hash tables want to store additional information
|
---|
145 | which each entry in the hash table. Some also find it
|
---|
146 | convenient to store additional information with the hash table
|
---|
147 | itself. This may be done using a derived hash table.
|
---|
148 |
|
---|
149 | Since C is not an object oriented language, creating a derived
|
---|
150 | hash table requires sticking together some boilerplate
|
---|
151 | routines with a few differences specific to the type of hash
|
---|
152 | table you want to create.
|
---|
153 |
|
---|
154 | An example of a derived hash table is the linker hash table.
|
---|
155 | The structures for this are defined in <<bfdlink.h>>. The
|
---|
156 | functions are in <<linker.c>>.
|
---|
157 |
|
---|
158 | You may also derive a hash table from an already derived hash
|
---|
159 | table. For example, the a.out linker backend code uses a hash
|
---|
160 | table derived from the linker hash table.
|
---|
161 |
|
---|
162 | @menu
|
---|
163 | @* Define the Derived Structures::
|
---|
164 | @* Write the Derived Creation Routine::
|
---|
165 | @* Write Other Derived Routines::
|
---|
166 | @end menu
|
---|
167 |
|
---|
168 | INODE
|
---|
169 | Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type
|
---|
170 | SUBSUBSECTION
|
---|
171 | Define the derived structures
|
---|
172 |
|
---|
173 | You must define a structure for an entry in the hash table,
|
---|
174 | and a structure for the hash table itself.
|
---|
175 |
|
---|
176 | The first field in the structure for an entry in the hash
|
---|
177 | table must be of the type used for an entry in the hash table
|
---|
178 | you are deriving from. If you are deriving from a basic hash
|
---|
179 | table this is <<struct bfd_hash_entry>>, which is defined in
|
---|
180 | <<bfd.h>>. The first field in the structure for the hash
|
---|
181 | table itself must be of the type of the hash table you are
|
---|
182 | deriving from itself. If you are deriving from a basic hash
|
---|
183 | table, this is <<struct bfd_hash_table>>.
|
---|
184 |
|
---|
185 | For example, the linker hash table defines <<struct
|
---|
186 | bfd_link_hash_entry>> (in <<bfdlink.h>>). The first field,
|
---|
187 | <<root>>, is of type <<struct bfd_hash_entry>>. Similarly,
|
---|
188 | the first field in <<struct bfd_link_hash_table>>, <<table>>,
|
---|
189 | is of type <<struct bfd_hash_table>>.
|
---|
190 |
|
---|
191 | INODE
|
---|
192 | Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type
|
---|
193 | SUBSUBSECTION
|
---|
194 | Write the derived creation routine
|
---|
195 |
|
---|
196 | You must write a routine which will create and initialize an
|
---|
197 | entry in the hash table. This routine is passed as the
|
---|
198 | function argument to <<bfd_hash_table_init>>.
|
---|
199 |
|
---|
200 | In order to permit other hash tables to be derived from the
|
---|
201 | hash table you are creating, this routine must be written in a
|
---|
202 | standard way.
|
---|
203 |
|
---|
204 | The first argument to the creation routine is a pointer to a
|
---|
205 | hash table entry. This may be <<NULL>>, in which case the
|
---|
206 | routine should allocate the right amount of space. Otherwise
|
---|
207 | the space has already been allocated by a hash table type
|
---|
208 | derived from this one.
|
---|
209 |
|
---|
210 | After allocating space, the creation routine must call the
|
---|
211 | creation routine of the hash table type it is derived from,
|
---|
212 | passing in a pointer to the space it just allocated. This
|
---|
213 | will initialize any fields used by the base hash table.
|
---|
214 |
|
---|
215 | Finally the creation routine must initialize any local fields
|
---|
216 | for the new hash table type.
|
---|
217 |
|
---|
218 | Here is a boilerplate example of a creation routine.
|
---|
219 | @var{function_name} is the name of the routine.
|
---|
220 | @var{entry_type} is the type of an entry in the hash table you
|
---|
221 | are creating. @var{base_newfunc} is the name of the creation
|
---|
222 | routine of the hash table type your hash table is derived
|
---|
223 | from.
|
---|
224 |
|
---|
225 | EXAMPLE
|
---|
226 |
|
---|
227 | .struct bfd_hash_entry *
|
---|
228 | .@var{function_name} (entry, table, string)
|
---|
229 | . struct bfd_hash_entry *entry;
|
---|
230 | . struct bfd_hash_table *table;
|
---|
231 | . const char *string;
|
---|
232 | .{
|
---|
233 | . struct @var{entry_type} *ret = (@var{entry_type} *) entry;
|
---|
234 | .
|
---|
235 | . {* Allocate the structure if it has not already been allocated by a
|
---|
236 | . derived class. *}
|
---|
237 | . if (ret == (@var{entry_type} *) NULL)
|
---|
238 | . {
|
---|
239 | . ret = ((@var{entry_type} *)
|
---|
240 | . bfd_hash_allocate (table, sizeof (@var{entry_type})));
|
---|
241 | . if (ret == (@var{entry_type} *) NULL)
|
---|
242 | . return NULL;
|
---|
243 | . }
|
---|
244 | .
|
---|
245 | . {* Call the allocation method of the base class. *}
|
---|
246 | . ret = ((@var{entry_type} *)
|
---|
247 | . @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string));
|
---|
248 | .
|
---|
249 | . {* Initialize the local fields here. *}
|
---|
250 | .
|
---|
251 | . return (struct bfd_hash_entry *) ret;
|
---|
252 | .}
|
---|
253 |
|
---|
254 | DESCRIPTION
|
---|
255 | The creation routine for the linker hash table, which is in
|
---|
256 | <<linker.c>>, looks just like this example.
|
---|
257 | @var{function_name} is <<_bfd_link_hash_newfunc>>.
|
---|
258 | @var{entry_type} is <<struct bfd_link_hash_entry>>.
|
---|
259 | @var{base_newfunc} is <<bfd_hash_newfunc>>, the creation
|
---|
260 | routine for a basic hash table.
|
---|
261 |
|
---|
262 | <<_bfd_link_hash_newfunc>> also initializes the local fields
|
---|
263 | in a linker hash table entry: <<type>>, <<written>> and
|
---|
264 | <<next>>.
|
---|
265 |
|
---|
266 | INODE
|
---|
267 | Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type
|
---|
268 | SUBSUBSECTION
|
---|
269 | Write other derived routines
|
---|
270 |
|
---|
271 | You will want to write other routines for your new hash table,
|
---|
272 | as well.
|
---|
273 |
|
---|
274 | You will want an initialization routine which calls the
|
---|
275 | initialization routine of the hash table you are deriving from
|
---|
276 | and initializes any other local fields. For the linker hash
|
---|
277 | table, this is <<_bfd_link_hash_table_init>> in <<linker.c>>.
|
---|
278 |
|
---|
279 | You will want a lookup routine which calls the lookup routine
|
---|
280 | of the hash table you are deriving from and casts the result.
|
---|
281 | The linker hash table uses <<bfd_link_hash_lookup>> in
|
---|
282 | <<linker.c>> (this actually takes an additional argument which
|
---|
283 | it uses to decide how to return the looked up value).
|
---|
284 |
|
---|
285 | You may want a traversal routine. This should just call the
|
---|
286 | traversal routine of the hash table you are deriving from with
|
---|
287 | appropriate casts. The linker hash table uses
|
---|
288 | <<bfd_link_hash_traverse>> in <<linker.c>>.
|
---|
289 |
|
---|
290 | These routines may simply be defined as macros. For example,
|
---|
291 | the a.out backend linker hash table, which is derived from the
|
---|
292 | linker hash table, uses macros for the lookup and traversal
|
---|
293 | routines. These are <<aout_link_hash_lookup>> and
|
---|
294 | <<aout_link_hash_traverse>> in aoutx.h.
|
---|
295 | */
|
---|
296 |
|
---|
297 | /* The default number of entries to use when creating a hash table. */
|
---|
298 | #define DEFAULT_SIZE (4051)
|
---|
299 |
|
---|
300 | /* Create a new hash table, given a number of entries. */
|
---|
301 |
|
---|
302 | boolean
|
---|
303 | bfd_hash_table_init_n (table, newfunc, size)
|
---|
304 | struct bfd_hash_table *table;
|
---|
305 | struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
|
---|
306 | struct bfd_hash_table *,
|
---|
307 | const char *));
|
---|
308 | unsigned int size;
|
---|
309 | {
|
---|
310 | unsigned int alloc;
|
---|
311 |
|
---|
312 | alloc = size * sizeof (struct bfd_hash_entry *);
|
---|
313 |
|
---|
314 | table->memory = (PTR) objalloc_create ();
|
---|
315 | if (table->memory == NULL)
|
---|
316 | {
|
---|
317 | bfd_set_error (bfd_error_no_memory);
|
---|
318 | return false;
|
---|
319 | }
|
---|
320 | table->table = ((struct bfd_hash_entry **)
|
---|
321 | objalloc_alloc ((struct objalloc *) table->memory, alloc));
|
---|
322 | if (table->table == NULL)
|
---|
323 | {
|
---|
324 | bfd_set_error (bfd_error_no_memory);
|
---|
325 | return false;
|
---|
326 | }
|
---|
327 | memset ((PTR) table->table, 0, alloc);
|
---|
328 | table->size = size;
|
---|
329 | table->newfunc = newfunc;
|
---|
330 | return true;
|
---|
331 | }
|
---|
332 |
|
---|
333 | /* Create a new hash table with the default number of entries. */
|
---|
334 |
|
---|
335 | boolean
|
---|
336 | bfd_hash_table_init (table, newfunc)
|
---|
337 | struct bfd_hash_table *table;
|
---|
338 | struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
|
---|
339 | struct bfd_hash_table *,
|
---|
340 | const char *));
|
---|
341 | {
|
---|
342 | return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE);
|
---|
343 | }
|
---|
344 |
|
---|
345 | /* Free a hash table. */
|
---|
346 |
|
---|
347 | void
|
---|
348 | bfd_hash_table_free (table)
|
---|
349 | struct bfd_hash_table *table;
|
---|
350 | {
|
---|
351 | objalloc_free ((struct objalloc *) table->memory);
|
---|
352 | table->memory = NULL;
|
---|
353 | }
|
---|
354 |
|
---|
355 | /* Look up a string in a hash table. */
|
---|
356 |
|
---|
357 | struct bfd_hash_entry *
|
---|
358 | bfd_hash_lookup (table, string, create, copy)
|
---|
359 | struct bfd_hash_table *table;
|
---|
360 | const char *string;
|
---|
361 | boolean create;
|
---|
362 | boolean copy;
|
---|
363 | {
|
---|
364 | register const unsigned char *s;
|
---|
365 | register unsigned long hash;
|
---|
366 | register unsigned int c;
|
---|
367 | struct bfd_hash_entry *hashp;
|
---|
368 | unsigned int len;
|
---|
369 | unsigned int index;
|
---|
370 |
|
---|
371 | hash = 0;
|
---|
372 | len = 0;
|
---|
373 | s = (const unsigned char *) string;
|
---|
374 | while ((c = *s++) != '\0')
|
---|
375 | {
|
---|
376 | hash += c + (c << 17);
|
---|
377 | hash ^= hash >> 2;
|
---|
378 | ++len;
|
---|
379 | }
|
---|
380 | hash += len + (len << 17);
|
---|
381 | hash ^= hash >> 2;
|
---|
382 |
|
---|
383 | index = hash % table->size;
|
---|
384 | for (hashp = table->table[index];
|
---|
385 | hashp != (struct bfd_hash_entry *) NULL;
|
---|
386 | hashp = hashp->next)
|
---|
387 | {
|
---|
388 | if (hashp->hash == hash
|
---|
389 | && strcmp (hashp->string, string) == 0)
|
---|
390 | return hashp;
|
---|
391 | }
|
---|
392 |
|
---|
393 | if (! create)
|
---|
394 | return (struct bfd_hash_entry *) NULL;
|
---|
395 |
|
---|
396 | hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string);
|
---|
397 | if (hashp == (struct bfd_hash_entry *) NULL)
|
---|
398 | return (struct bfd_hash_entry *) NULL;
|
---|
399 | if (copy)
|
---|
400 | {
|
---|
401 | char *new;
|
---|
402 |
|
---|
403 | new = (char *) objalloc_alloc ((struct objalloc *) table->memory,
|
---|
404 | len + 1);
|
---|
405 | if (!new)
|
---|
406 | {
|
---|
407 | bfd_set_error (bfd_error_no_memory);
|
---|
408 | return (struct bfd_hash_entry *) NULL;
|
---|
409 | }
|
---|
410 | strcpy (new, string);
|
---|
411 | string = new;
|
---|
412 | }
|
---|
413 | hashp->string = string;
|
---|
414 | hashp->hash = hash;
|
---|
415 | hashp->next = table->table[index];
|
---|
416 | table->table[index] = hashp;
|
---|
417 |
|
---|
418 | return hashp;
|
---|
419 | }
|
---|
420 |
|
---|
421 | /* Replace an entry in a hash table. */
|
---|
422 |
|
---|
423 | void
|
---|
424 | bfd_hash_replace (table, old, nw)
|
---|
425 | struct bfd_hash_table *table;
|
---|
426 | struct bfd_hash_entry *old;
|
---|
427 | struct bfd_hash_entry *nw;
|
---|
428 | {
|
---|
429 | unsigned int index;
|
---|
430 | struct bfd_hash_entry **pph;
|
---|
431 |
|
---|
432 | index = old->hash % table->size;
|
---|
433 | for (pph = &table->table[index];
|
---|
434 | (*pph) != (struct bfd_hash_entry *) NULL;
|
---|
435 | pph = &(*pph)->next)
|
---|
436 | {
|
---|
437 | if (*pph == old)
|
---|
438 | {
|
---|
439 | *pph = nw;
|
---|
440 | return;
|
---|
441 | }
|
---|
442 | }
|
---|
443 |
|
---|
444 | abort ();
|
---|
445 | }
|
---|
446 |
|
---|
447 | /* Base method for creating a new hash table entry. */
|
---|
448 |
|
---|
449 | /*ARGSUSED*/
|
---|
450 | struct bfd_hash_entry *
|
---|
451 | bfd_hash_newfunc (entry, table, string)
|
---|
452 | struct bfd_hash_entry *entry;
|
---|
453 | struct bfd_hash_table *table;
|
---|
454 | const char *string ATTRIBUTE_UNUSED;
|
---|
455 | {
|
---|
456 | if (entry == (struct bfd_hash_entry *) NULL)
|
---|
457 | entry = ((struct bfd_hash_entry *)
|
---|
458 | bfd_hash_allocate (table, sizeof (struct bfd_hash_entry)));
|
---|
459 | return entry;
|
---|
460 | }
|
---|
461 |
|
---|
462 | /* Allocate space in a hash table. */
|
---|
463 |
|
---|
464 | PTR
|
---|
465 | bfd_hash_allocate (table, size)
|
---|
466 | struct bfd_hash_table *table;
|
---|
467 | unsigned int size;
|
---|
468 | {
|
---|
469 | PTR ret;
|
---|
470 |
|
---|
471 | ret = objalloc_alloc ((struct objalloc *) table->memory, size);
|
---|
472 | if (ret == NULL && size != 0)
|
---|
473 | bfd_set_error (bfd_error_no_memory);
|
---|
474 | return ret;
|
---|
475 | }
|
---|
476 |
|
---|
477 | /* Traverse a hash table. */
|
---|
478 |
|
---|
479 | void
|
---|
480 | bfd_hash_traverse (table, func, info)
|
---|
481 | struct bfd_hash_table *table;
|
---|
482 | boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR));
|
---|
483 | PTR info;
|
---|
484 | {
|
---|
485 | unsigned int i;
|
---|
486 |
|
---|
487 | for (i = 0; i < table->size; i++)
|
---|
488 | {
|
---|
489 | struct bfd_hash_entry *p;
|
---|
490 |
|
---|
491 | for (p = table->table[i]; p != NULL; p = p->next)
|
---|
492 | {
|
---|
493 | if (! (*func) (p, info))
|
---|
494 | return;
|
---|
495 | }
|
---|
496 | }
|
---|
497 | }
|
---|
498 | |
---|
499 |
|
---|
500 | /* A few different object file formats (a.out, COFF, ELF) use a string
|
---|
501 | table. These functions support adding strings to a string table,
|
---|
502 | returning the byte offset, and writing out the table.
|
---|
503 |
|
---|
504 | Possible improvements:
|
---|
505 | + look for strings matching trailing substrings of other strings
|
---|
506 | + better data structures? balanced trees?
|
---|
507 | + look at reducing memory use elsewhere -- maybe if we didn't have
|
---|
508 | to construct the entire symbol table at once, we could get by
|
---|
509 | with smaller amounts of VM? (What effect does that have on the
|
---|
510 | string table reductions?) */
|
---|
511 |
|
---|
512 | /* An entry in the strtab hash table. */
|
---|
513 |
|
---|
514 | struct strtab_hash_entry
|
---|
515 | {
|
---|
516 | struct bfd_hash_entry root;
|
---|
517 | /* Index in string table. */
|
---|
518 | bfd_size_type index;
|
---|
519 | /* Next string in strtab. */
|
---|
520 | struct strtab_hash_entry *next;
|
---|
521 | };
|
---|
522 |
|
---|
523 | /* The strtab hash table. */
|
---|
524 |
|
---|
525 | struct bfd_strtab_hash
|
---|
526 | {
|
---|
527 | struct bfd_hash_table table;
|
---|
528 | /* Size of strtab--also next available index. */
|
---|
529 | bfd_size_type size;
|
---|
530 | /* First string in strtab. */
|
---|
531 | struct strtab_hash_entry *first;
|
---|
532 | /* Last string in strtab. */
|
---|
533 | struct strtab_hash_entry *last;
|
---|
534 | /* Whether to precede strings with a two byte length, as in the
|
---|
535 | XCOFF .debug section. */
|
---|
536 | boolean xcoff;
|
---|
537 | };
|
---|
538 |
|
---|
539 | static struct bfd_hash_entry *strtab_hash_newfunc
|
---|
540 | PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
|
---|
541 |
|
---|
542 | /* Routine to create an entry in a strtab. */
|
---|
543 |
|
---|
544 | static struct bfd_hash_entry *
|
---|
545 | strtab_hash_newfunc (entry, table, string)
|
---|
546 | struct bfd_hash_entry *entry;
|
---|
547 | struct bfd_hash_table *table;
|
---|
548 | const char *string;
|
---|
549 | {
|
---|
550 | struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry;
|
---|
551 |
|
---|
552 | /* Allocate the structure if it has not already been allocated by a
|
---|
553 | subclass. */
|
---|
554 | if (ret == (struct strtab_hash_entry *) NULL)
|
---|
555 | ret = ((struct strtab_hash_entry *)
|
---|
556 | bfd_hash_allocate (table, sizeof (struct strtab_hash_entry)));
|
---|
557 | if (ret == (struct strtab_hash_entry *) NULL)
|
---|
558 | return NULL;
|
---|
559 |
|
---|
560 | /* Call the allocation method of the superclass. */
|
---|
561 | ret = ((struct strtab_hash_entry *)
|
---|
562 | bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
|
---|
563 |
|
---|
564 | if (ret)
|
---|
565 | {
|
---|
566 | /* Initialize the local fields. */
|
---|
567 | ret->index = (bfd_size_type) -1;
|
---|
568 | ret->next = NULL;
|
---|
569 | }
|
---|
570 |
|
---|
571 | return (struct bfd_hash_entry *) ret;
|
---|
572 | }
|
---|
573 |
|
---|
574 | /* Look up an entry in an strtab. */
|
---|
575 |
|
---|
576 | #define strtab_hash_lookup(t, string, create, copy) \
|
---|
577 | ((struct strtab_hash_entry *) \
|
---|
578 | bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
|
---|
579 |
|
---|
580 | /* Create a new strtab. */
|
---|
581 |
|
---|
582 | struct bfd_strtab_hash *
|
---|
583 | _bfd_stringtab_init ()
|
---|
584 | {
|
---|
585 | struct bfd_strtab_hash *table;
|
---|
586 |
|
---|
587 | table = ((struct bfd_strtab_hash *)
|
---|
588 | bfd_malloc (sizeof (struct bfd_strtab_hash)));
|
---|
589 | if (table == NULL)
|
---|
590 | return NULL;
|
---|
591 |
|
---|
592 | if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc))
|
---|
593 | {
|
---|
594 | free (table);
|
---|
595 | return NULL;
|
---|
596 | }
|
---|
597 |
|
---|
598 | table->size = 0;
|
---|
599 | table->first = NULL;
|
---|
600 | table->last = NULL;
|
---|
601 | table->xcoff = false;
|
---|
602 |
|
---|
603 | return table;
|
---|
604 | }
|
---|
605 |
|
---|
606 | /* Create a new strtab in which the strings are output in the format
|
---|
607 | used in the XCOFF .debug section: a two byte length precedes each
|
---|
608 | string. */
|
---|
609 |
|
---|
610 | struct bfd_strtab_hash *
|
---|
611 | _bfd_xcoff_stringtab_init ()
|
---|
612 | {
|
---|
613 | struct bfd_strtab_hash *ret;
|
---|
614 |
|
---|
615 | ret = _bfd_stringtab_init ();
|
---|
616 | if (ret != NULL)
|
---|
617 | ret->xcoff = true;
|
---|
618 | return ret;
|
---|
619 | }
|
---|
620 |
|
---|
621 | /* Free a strtab. */
|
---|
622 |
|
---|
623 | void
|
---|
624 | _bfd_stringtab_free (table)
|
---|
625 | struct bfd_strtab_hash *table;
|
---|
626 | {
|
---|
627 | bfd_hash_table_free (&table->table);
|
---|
628 | free (table);
|
---|
629 | }
|
---|
630 |
|
---|
631 | /* Get the index of a string in a strtab, adding it if it is not
|
---|
632 | already present. If HASH is false, we don't really use the hash
|
---|
633 | table, and we don't eliminate duplicate strings. */
|
---|
634 |
|
---|
635 | bfd_size_type
|
---|
636 | _bfd_stringtab_add (tab, str, hash, copy)
|
---|
637 | struct bfd_strtab_hash *tab;
|
---|
638 | const char *str;
|
---|
639 | boolean hash;
|
---|
640 | boolean copy;
|
---|
641 | {
|
---|
642 | register struct strtab_hash_entry *entry;
|
---|
643 |
|
---|
644 | if (hash)
|
---|
645 | {
|
---|
646 | entry = strtab_hash_lookup (tab, str, true, copy);
|
---|
647 | if (entry == NULL)
|
---|
648 | return (bfd_size_type) -1;
|
---|
649 | }
|
---|
650 | else
|
---|
651 | {
|
---|
652 | entry = ((struct strtab_hash_entry *)
|
---|
653 | bfd_hash_allocate (&tab->table,
|
---|
654 | sizeof (struct strtab_hash_entry)));
|
---|
655 | if (entry == NULL)
|
---|
656 | return (bfd_size_type) -1;
|
---|
657 | if (! copy)
|
---|
658 | entry->root.string = str;
|
---|
659 | else
|
---|
660 | {
|
---|
661 | char *n;
|
---|
662 |
|
---|
663 | n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1);
|
---|
664 | if (n == NULL)
|
---|
665 | return (bfd_size_type) -1;
|
---|
666 | entry->root.string = n;
|
---|
667 | }
|
---|
668 | entry->index = (bfd_size_type) -1;
|
---|
669 | entry->next = NULL;
|
---|
670 | }
|
---|
671 |
|
---|
672 | if (entry->index == (bfd_size_type) -1)
|
---|
673 | {
|
---|
674 | entry->index = tab->size;
|
---|
675 | tab->size += strlen (str) + 1;
|
---|
676 | if (tab->xcoff)
|
---|
677 | {
|
---|
678 | entry->index += 2;
|
---|
679 | tab->size += 2;
|
---|
680 | }
|
---|
681 | if (tab->first == NULL)
|
---|
682 | tab->first = entry;
|
---|
683 | else
|
---|
684 | tab->last->next = entry;
|
---|
685 | tab->last = entry;
|
---|
686 | }
|
---|
687 |
|
---|
688 | return entry->index;
|
---|
689 | }
|
---|
690 |
|
---|
691 | /* Get the number of bytes in a strtab. */
|
---|
692 |
|
---|
693 | bfd_size_type
|
---|
694 | _bfd_stringtab_size (tab)
|
---|
695 | struct bfd_strtab_hash *tab;
|
---|
696 | {
|
---|
697 | return tab->size;
|
---|
698 | }
|
---|
699 |
|
---|
700 | /* Write out a strtab. ABFD must already be at the right location in
|
---|
701 | the file. */
|
---|
702 |
|
---|
703 | boolean
|
---|
704 | _bfd_stringtab_emit (abfd, tab)
|
---|
705 | register bfd *abfd;
|
---|
706 | struct bfd_strtab_hash *tab;
|
---|
707 | {
|
---|
708 | register boolean xcoff;
|
---|
709 | register struct strtab_hash_entry *entry;
|
---|
710 |
|
---|
711 | xcoff = tab->xcoff;
|
---|
712 |
|
---|
713 | for (entry = tab->first; entry != NULL; entry = entry->next)
|
---|
714 | {
|
---|
715 | register const char *str;
|
---|
716 | register size_t len;
|
---|
717 |
|
---|
718 | str = entry->root.string;
|
---|
719 | len = strlen (str) + 1;
|
---|
720 |
|
---|
721 | if (xcoff)
|
---|
722 | {
|
---|
723 | bfd_byte buf[2];
|
---|
724 |
|
---|
725 | /* The output length includes the null byte. */
|
---|
726 | bfd_put_16 (abfd, len, buf);
|
---|
727 | if (bfd_write ((PTR) buf, 1, 2, abfd) != 2)
|
---|
728 | return false;
|
---|
729 | }
|
---|
730 |
|
---|
731 | if (bfd_write ((PTR) str, 1, len, abfd) != len)
|
---|
732 | return false;
|
---|
733 | }
|
---|
734 |
|
---|
735 | return true;
|
---|
736 | }
|
---|