1 /* ELF/DWARF string table handling.
2 Copyright (C) 2000, 2001, 2002, 2005, 2016 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 "libdwelfP.h"
50 struct Dwelf_Strent *next;
51 struct Dwelf_Strent *left;
52 struct Dwelf_Strent *right;
60 struct memoryblock *next;
67 struct Dwelf_Strent *root;
68 struct memoryblock *memory;
74 struct Dwelf_Strent null;
78 /* Cache for the pagesize. */
80 /* We correct this value a bit so that `malloc' is not allocating more
82 #define MALLOC_OVERHEAD (2 * sizeof (void *))
86 dwelf_strtab_init (bool nullstr)
90 ps = sysconf (_SC_PAGESIZE);
91 assert (sizeof (struct memoryblock) < ps - MALLOC_OVERHEAD);
95 = (Dwelf_Strtab *) calloc (1, sizeof (struct Dwelf_Strtab));
98 ret->nullstr = nullstr;
103 ret->null.string = "";
112 morememory (Dwelf_Strtab *st, size_t len)
114 size_t overhead = offsetof (struct memoryblock, memory);
115 len += overhead + MALLOC_OVERHEAD;
117 /* Allocate nearest multiple of pagesize >= len. */
118 len = ((len / ps) + (len % ps != 0)) * ps - MALLOC_OVERHEAD;
120 struct memoryblock *newmem = (struct memoryblock *) malloc (len);
124 newmem->next = st->memory;
126 st->backp = newmem->memory;
127 st->left = len - overhead;
134 dwelf_strtab_free (Dwelf_Strtab *st)
136 struct memoryblock *mb = st->memory;
149 static Dwelf_Strent *
150 newstring (Dwelf_Strtab *st, const char *str, size_t len)
152 /* Compute the amount of padding needed to make the structure aligned. */
153 size_t align = ((__alignof__ (struct Dwelf_Strent)
154 - (((uintptr_t) st->backp)
155 & (__alignof__ (struct Dwelf_Strent) - 1)))
156 & (__alignof__ (struct Dwelf_Strent) - 1));
158 /* Make sure there is enough room in the memory block. */
159 if (st->left < align + sizeof (struct Dwelf_Strent) + len)
161 if (morememory (st, sizeof (struct Dwelf_Strent) + len))
167 /* Create the reserved string. */
168 Dwelf_Strent *newstr = (Dwelf_Strent *) (st->backp + align);
169 newstr->string = str;
173 newstr->right = NULL;
175 for (int i = len - 2; i >= 0; --i)
176 newstr->reverse[i] = str[len - 2 - i];
177 newstr->reverse[len - 1] = '\0';
178 st->backp += align + sizeof (struct Dwelf_Strent) + len;
179 st->left -= align + sizeof (struct Dwelf_Strent) + len;
185 /* XXX This function should definitely be rewritten to use a balancing
186 tree algorith (AVL, red-black trees). For now a simple, correct
187 implementation is enough. */
188 static Dwelf_Strent **
189 searchstring (Dwelf_Strent **sep, Dwelf_Strent *newstr)
198 /* Compare the strings. */
199 int cmpres = memcmp ((*sep)->reverse, newstr->reverse,
200 MIN ((*sep)->len, newstr->len) - 1);
202 /* We found a matching string. */
205 return searchstring (&(*sep)->left, newstr);
207 return searchstring (&(*sep)->right, newstr);
211 /* Add new string. The actual string is assumed to be permanent. */
212 static Dwelf_Strent *
213 strtab_add (Dwelf_Strtab *st, const char *str, size_t len)
215 /* Make sure all "" strings get offset 0 but only if the table was
216 created with a special null entry in mind. */
217 if (len == 1 && st->null.string != NULL)
220 /* Allocate memory for the new string and its associated information. */
221 Dwelf_Strent *newstr = newstring (st, str, len);
225 /* Search in the array for the place to insert the string. If there
226 is no string with matching prefix and no string with matching
227 leading substring, create a new entry. */
228 Dwelf_Strent **sep = searchstring (&st->root, newstr);
231 /* This is not the same entry. This means we have a prefix match. */
232 if ((*sep)->len > newstr->len)
234 /* Check whether we already know this string. */
235 for (Dwelf_Strent *subs = (*sep)->next; subs != NULL;
237 if (subs->len == newstr->len)
239 /* We have an exact match with a substring. Free the memory
241 st->left += st->backp - (char *) newstr;
242 st->backp = (char *) newstr;
247 /* We have a new substring. This means we don't need the reverse
248 string of this entry anymore. */
249 st->backp -= newstr->len;
250 st->left += newstr->len;
252 newstr->next = (*sep)->next;
253 (*sep)->next = newstr;
255 else if ((*sep)->len != newstr->len)
257 /* When we get here it means that the string we are about to
258 add has a common prefix with a string we already have but
259 it is longer. In this case we have to put it first. */
260 st->total += newstr->len - (*sep)->len;
262 newstr->left = (*sep)->left;
263 newstr->right = (*sep)->right;
268 /* We have an exact match. Free the memory we allocated. */
269 st->left += st->backp - (char *) newstr;
270 st->backp = (char *) newstr;
276 st->total += newstr->len;
282 dwelf_strtab_add (Dwelf_Strtab *st, const char *str)
284 return strtab_add (st, str, strlen (str) + 1);
288 dwelf_strtab_add_len (Dwelf_Strtab *st, const char *str, size_t len)
290 return strtab_add (st, str, len);
294 copystrings (Dwelf_Strent *nodep, char **freep, size_t *offsetp)
296 if (nodep->left != NULL)
297 copystrings (nodep->left, freep, offsetp);
299 /* Process the current node. */
300 nodep->offset = *offsetp;
301 *freep = (char *) mempcpy (*freep, nodep->string, nodep->len);
302 *offsetp += nodep->len;
304 for (Dwelf_Strent *subs = nodep->next; subs != NULL; subs = subs->next)
306 assert (subs->len < nodep->len);
307 subs->offset = nodep->offset + nodep->len - subs->len;
308 assert (subs->offset != 0 || subs->string[0] == '\0');
311 if (nodep->right != NULL)
312 copystrings (nodep->right, freep, offsetp);
317 dwelf_strtab_finalize (Dwelf_Strtab *st, Elf_Data *data)
319 size_t nulllen = st->nullstr ? 1 : 0;
321 /* Fill in the information. */
322 data->d_buf = malloc (st->total + nulllen);
323 if (data->d_buf == NULL)
326 /* The first byte must always be zero if we created the table with a
329 *((char *) data->d_buf) = '\0';
331 data->d_type = ELF_T_BYTE;
332 data->d_size = st->total + nulllen;
335 data->d_version = EV_CURRENT;
337 /* Now run through the tree and add all the string while also updating
338 the offset members of the elfstrent records. */
339 char *endp = (char *) data->d_buf + nulllen;
340 size_t copylen = nulllen;
342 copystrings (st->root, &endp, ©len);
343 assert (copylen == st->total + nulllen);
350 dwelf_strent_off (Dwelf_Strent *se)
357 dwelf_strent_str (Dwelf_Strent *se)