00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "bfd.h"
00026 #include "sysdep.h"
00027 #include "libbfd.h"
00028 #include "elf-bfd.h"
00029 #include "hashtab.h"
00030 #include "libiberty.h"
00031
00032
00033
00034 struct elf_strtab_hash_entry
00035 {
00036 struct bfd_hash_entry root;
00037
00038 int len;
00039 unsigned int refcount;
00040 union {
00041
00042 bfd_size_type index;
00043
00044 struct elf_strtab_hash_entry *suffix;
00045 } u;
00046 };
00047
00048
00049
00050 struct elf_strtab_hash
00051 {
00052 struct bfd_hash_table table;
00053
00054 bfd_size_type size;
00055
00056 bfd_size_type alloced;
00057
00058 bfd_size_type sec_size;
00059
00060 struct elf_strtab_hash_entry **array;
00061 };
00062
00063
00064
00065 static struct bfd_hash_entry *
00066 elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
00067 struct bfd_hash_table *table,
00068 const char *string)
00069 {
00070
00071
00072 if (entry == NULL)
00073 entry = bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
00074 if (entry == NULL)
00075 return NULL;
00076
00077
00078 entry = bfd_hash_newfunc (entry, table, string);
00079
00080 if (entry)
00081 {
00082
00083 struct elf_strtab_hash_entry *ret;
00084
00085 ret = (struct elf_strtab_hash_entry *) entry;
00086 ret->u.index = -1;
00087 ret->refcount = 0;
00088 ret->len = 0;
00089 }
00090
00091 return entry;
00092 }
00093
00094
00095
00096 struct elf_strtab_hash *
00097 _bfd_elf_strtab_init (void)
00098 {
00099 struct elf_strtab_hash *table;
00100 bfd_size_type amt = sizeof (struct elf_strtab_hash);
00101
00102 table = bfd_malloc (amt);
00103 if (table == NULL)
00104 return NULL;
00105
00106 if (! bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc))
00107 {
00108 free (table);
00109 return NULL;
00110 }
00111
00112 table->sec_size = 0;
00113 table->size = 1;
00114 table->alloced = 64;
00115 amt = sizeof (struct elf_strtab_hasn_entry *);
00116 table->array = bfd_malloc (table->alloced * amt);
00117 if (table->array == NULL)
00118 {
00119 free (table);
00120 return NULL;
00121 }
00122
00123 table->array[0] = NULL;
00124
00125 return table;
00126 }
00127
00128
00129
00130 void
00131 _bfd_elf_strtab_free (struct elf_strtab_hash *tab)
00132 {
00133 bfd_hash_table_free (&tab->table);
00134 free (tab->array);
00135 free (tab);
00136 }
00137
00138
00139
00140
00141 bfd_size_type
00142 _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
00143 const char *str,
00144 bfd_boolean copy)
00145 {
00146 register struct elf_strtab_hash_entry *entry;
00147
00148
00149
00150 if (*str == '\0')
00151 return 0;
00152
00153 BFD_ASSERT (tab->sec_size == 0);
00154 entry = (struct elf_strtab_hash_entry *)
00155 bfd_hash_lookup (&tab->table, str, TRUE, copy);
00156
00157 if (entry == NULL)
00158 return (bfd_size_type) -1;
00159
00160 entry->refcount++;
00161 if (entry->len == 0)
00162 {
00163 entry->len = strlen (str) + 1;
00164
00165 BFD_ASSERT (entry->len > 0);
00166 if (tab->size == tab->alloced)
00167 {
00168 bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
00169 tab->alloced *= 2;
00170 tab->array = bfd_realloc (tab->array, tab->alloced * amt);
00171 if (tab->array == NULL)
00172 return (bfd_size_type) -1;
00173 }
00174
00175 entry->u.index = tab->size++;
00176 tab->array[entry->u.index] = entry;
00177 }
00178 return entry->u.index;
00179 }
00180
00181 void
00182 _bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
00183 {
00184 if (idx == 0 || idx == (bfd_size_type) -1)
00185 return;
00186 BFD_ASSERT (tab->sec_size == 0);
00187 BFD_ASSERT (idx < tab->size);
00188 ++tab->array[idx]->refcount;
00189 }
00190
00191 void
00192 _bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
00193 {
00194 if (idx == 0 || idx == (bfd_size_type) -1)
00195 return;
00196 BFD_ASSERT (tab->sec_size == 0);
00197 BFD_ASSERT (idx < tab->size);
00198 BFD_ASSERT (tab->array[idx]->refcount > 0);
00199 --tab->array[idx]->refcount;
00200 }
00201
00202 void
00203 _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
00204 {
00205 bfd_size_type idx;
00206
00207 for (idx = 1; idx < tab->size; ++idx)
00208 tab->array[idx]->refcount = 0;
00209 }
00210
00211 bfd_size_type
00212 _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
00213 {
00214 return tab->sec_size ? tab->sec_size : tab->size;
00215 }
00216
00217 bfd_size_type
00218 _bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
00219 {
00220 struct elf_strtab_hash_entry *entry;
00221
00222 if (idx == 0)
00223 return 0;
00224 BFD_ASSERT (idx < tab->size);
00225 BFD_ASSERT (tab->sec_size);
00226 entry = tab->array[idx];
00227 BFD_ASSERT (entry->refcount > 0);
00228 entry->refcount--;
00229 return tab->array[idx]->u.index;
00230 }
00231
00232 bfd_boolean
00233 _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
00234 {
00235 bfd_size_type off = 1, i;
00236
00237 if (bfd_bwrite ("", 1, abfd) != 1)
00238 return FALSE;
00239
00240 for (i = 1; i < tab->size; ++i)
00241 {
00242 register const char *str;
00243 register unsigned int len;
00244
00245 BFD_ASSERT (tab->array[i]->refcount == 0);
00246 len = tab->array[i]->len;
00247 if ((int) len < 0)
00248 continue;
00249
00250 str = tab->array[i]->root.string;
00251 if (bfd_bwrite (str, len, abfd) != len)
00252 return FALSE;
00253
00254 off += len;
00255 }
00256
00257 BFD_ASSERT (off == tab->sec_size);
00258 return TRUE;
00259 }
00260
00261
00262
00263 static int
00264 strrevcmp (const void *a, const void *b)
00265 {
00266 struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
00267 struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
00268 unsigned int lenA = A->len;
00269 unsigned int lenB = B->len;
00270 const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
00271 const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
00272 int l = lenA < lenB ? lenA : lenB;
00273
00274 while (l)
00275 {
00276 if (*s != *t)
00277 return (int) *s - (int) *t;
00278 s--;
00279 t--;
00280 l--;
00281 }
00282 return lenA - lenB;
00283 }
00284
00285 static inline int
00286 is_suffix (const struct elf_strtab_hash_entry *A,
00287 const struct elf_strtab_hash_entry *B)
00288 {
00289 if (A->len <= B->len)
00290
00291
00292 return 0;
00293
00294 return memcmp (A->root.string + (A->len - B->len),
00295 B->root.string, B->len - 1) == 0;
00296 }
00297
00298
00299
00300
00301 void
00302 _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
00303 {
00304 struct elf_strtab_hash_entry **array, **a, *e;
00305 bfd_size_type size, amt;
00306
00307
00308
00309
00310
00311 size_t i;
00312
00313
00314 amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
00315 array = bfd_malloc (amt);
00316 if (array == NULL)
00317 goto alloc_failure;
00318
00319 for (i = 1, a = array; i < tab->size; ++i)
00320 {
00321 e = tab->array[i];
00322 if (e->refcount)
00323 {
00324 *a++ = e;
00325
00326 e->len -= 1;
00327 }
00328 else
00329 e->len = 0;
00330 }
00331
00332 size = a - array;
00333 if (size != 0)
00334 {
00335 qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 e = *--a;
00352 e->len += 1;
00353 while (--a >= array)
00354 {
00355 struct elf_strtab_hash_entry *cmp = *a;
00356
00357 cmp->len += 1;
00358 if (is_suffix (e, cmp))
00359 {
00360 cmp->u.suffix = e;
00361 cmp->len = -cmp->len;
00362 }
00363 else
00364 e = cmp;
00365 }
00366 }
00367
00368 alloc_failure:
00369 if (array)
00370 free (array);
00371
00372
00373 size = 1;
00374 for (i = 1; i < tab->size; ++i)
00375 {
00376 e = tab->array[i];
00377 if (e->refcount && e->len > 0)
00378 {
00379 e->u.index = size;
00380 size += e->len;
00381 }
00382 }
00383
00384 tab->sec_size = size;
00385
00386
00387 for (i = 1; i < tab->size; ++i)
00388 {
00389 e = tab->array[i];
00390 if (e->refcount && e->len < 0)
00391 e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
00392 }
00393 }