1 /* ELF string table handling.
2 Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
3 This file is part of elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
9 * the GNU Lesser General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at
11 your option) any later version
15 * the GNU General Public License as published by the Free
16 Software Foundation; either version 2 of the License, or (at
17 your option) any later version
19 or both in parallel, as here.
21 elfutils is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
26 You should have received copies of the GNU General Public License and
27 the GNU Lesser General Public License along with this program. If
28 not, see <http://www.gnu.org/licenses/>. */
42 #include <sys/param.h>
48 # define MIN(a, b) ((a) < (b) ? (a) : (b))
54 const wchar_t *string;
56 struct Ebl_WStrent *next;
57 struct Ebl_WStrent *left;
58 struct Ebl_WStrent *right;
66 struct memoryblock *next;
73 struct Ebl_WStrent *root;
74 struct memoryblock *memory;
80 struct Ebl_WStrent null;
84 /* Cache for the pagesize. We correct this value a bit so that `malloc'
85 is not allocating more than a page. */
90 ebl_wstrtabinit (bool nullstr)
92 struct Ebl_WStrtab *ret;
96 ps = sysconf (_SC_PAGESIZE) - 2 * sizeof (void *);
97 assert (sizeof (struct memoryblock) < ps);
100 ret = (struct Ebl_WStrtab *) calloc (1, sizeof (struct Ebl_WStrtab));
103 ret->nullstr = nullstr;
107 ret->null.string = L"";
115 morememory (struct Ebl_WStrtab *st, size_t len)
117 struct memoryblock *newmem;
121 newmem = (struct memoryblock *) malloc (len);
125 newmem->next = st->memory;
127 st->backp = newmem->memory;
128 st->left = len - offsetof (struct memoryblock, memory);
135 ebl_wstrtabfree (struct Ebl_WStrtab *st)
137 struct memoryblock *mb = st->memory;
150 static struct Ebl_WStrent *
151 newstring (struct Ebl_WStrtab *st, const wchar_t *str, size_t len)
153 struct Ebl_WStrent *newstr;
157 /* Compute the amount of padding needed to make the structure aligned. */
158 align = ((__alignof__ (struct Ebl_WStrent)
159 - (((uintptr_t) st->backp)
160 & (__alignof__ (struct Ebl_WStrent) - 1)))
161 & (__alignof__ (struct Ebl_WStrent) - 1));
163 /* Make sure there is enough room in the memory block. */
164 if (st->left < align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t))
167 sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t)))
173 /* Create the reserved string. */
174 newstr = (struct Ebl_WStrent *) (st->backp + align);
175 newstr->string = str;
179 newstr->right = NULL;
181 for (i = len - 2; i >= 0; --i)
182 newstr->reverse[i] = str[len - 2 - i];
183 newstr->reverse[len - 1] = L'\0';
184 st->backp += align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t);
185 st->left -= align + sizeof (struct Ebl_WStrent) + len * sizeof (wchar_t);
191 /* XXX This function should definitely be rewritten to use a balancing
192 tree algorith (AVL, red-black trees). For now a simple, correct
193 implementation is enough. */
194 static struct Ebl_WStrent **
195 searchstring (struct Ebl_WStrent **sep, struct Ebl_WStrent *newstr)
206 /* Compare the strings. */
207 cmpres = wmemcmp ((*sep)->reverse, newstr->reverse,
208 MIN ((*sep)->len, newstr->len) - 1);
210 /* We found a matching string. */
213 return searchstring (&(*sep)->left, newstr);
215 return searchstring (&(*sep)->right, newstr);
219 /* Add new string. The actual string is assumed to be permanent. */
221 ebl_wstrtabadd (struct Ebl_WStrtab *st, const wchar_t *str, size_t len)
223 struct Ebl_WStrent *newstr;
224 struct Ebl_WStrent **sep;
226 /* Compute the string length if the caller doesn't know it. */
228 len = wcslen (str) + 1;
230 /* Make sure all "" strings get offset 0 but only if the table was
231 created with a special null entry in mind. */
232 if (len == 1 && st->null.string != NULL)
235 /* Allocate memory for the new string and its associated information. */
236 newstr = newstring (st, str, len);
240 /* Search in the array for the place to insert the string. If there
241 is no string with matching prefix and no string with matching
242 leading substring, create a new entry. */
243 sep = searchstring (&st->root, newstr);
246 /* This is not the same entry. This means we have a prefix match. */
247 if ((*sep)->len > newstr->len)
249 struct Ebl_WStrent *subs;
251 /* Check whether we already know this string. */
252 for (subs = (*sep)->next; subs != NULL; subs = subs->next)
253 if (subs->len == newstr->len)
255 /* We have an exact match with a substring. Free the memory
257 st->left += st->backp - (char *) newstr;
258 st->backp = (char *) newstr;
263 /* We have a new substring. This means we don't need the reverse
264 string of this entry anymore. */
265 st->backp -= newstr->len;
266 st->left += newstr->len;
268 newstr->next = (*sep)->next;
269 (*sep)->next = newstr;
271 else if ((*sep)->len != newstr->len)
273 /* When we get here it means that the string we are about to
274 add has a common prefix with a string we already have but
275 it is longer. In this case we have to put it first. */
276 st->total += newstr->len - (*sep)->len;
278 newstr->left = (*sep)->left;
279 newstr->right = (*sep)->right;
284 /* We have an exact match. Free the memory we allocated. */
285 st->left += st->backp - (char *) newstr;
286 st->backp = (char *) newstr;
292 st->total += newstr->len;
299 copystrings (struct Ebl_WStrent *nodep, wchar_t **freep, size_t *offsetp)
301 struct Ebl_WStrent *subs;
303 if (nodep->left != NULL)
304 copystrings (nodep->left, freep, offsetp);
306 /* Process the current node. */
307 nodep->offset = *offsetp;
308 *freep = wmempcpy (*freep, nodep->string, nodep->len);
309 *offsetp += nodep->len * sizeof (wchar_t);
311 for (subs = nodep->next; subs != NULL; subs = subs->next)
313 assert (subs->len < nodep->len);
314 subs->offset = nodep->offset + nodep->len - subs->len;
315 assert (subs->offset != 0 || subs->string[0] == '\0');
318 if (nodep->right != NULL)
319 copystrings (nodep->right, freep, offsetp);
324 ebl_wstrtabfinalize (struct Ebl_WStrtab *st, Elf_Data *data)
328 size_t nulllen = st->nullstr ? 1 : 0;
330 /* Fill in the information. */
331 data->d_buf = malloc ((st->total + nulllen) * sizeof (wchar_t));
332 if (data->d_buf == NULL)
335 /* The first byte must always be zero if we created the table with a
338 *((wchar_t *) data->d_buf) = L'\0';
340 data->d_type = ELF_T_BYTE;
341 data->d_size = st->total + nulllen;
344 data->d_version = EV_CURRENT;
346 /* Now run through the tree and add all the string while also updating
347 the offset members of the elfstrent records. */
348 endp = (wchar_t *) data->d_buf + nulllen;
349 copylen = sizeof (wchar_t) * nulllen;
350 copystrings (st->root, &endp, ©len);
351 assert (copylen == (st->total + nulllen) * sizeof (wchar_t));
356 ebl_wstrtaboffset (struct Ebl_WStrent *se)