xref: /freebsd-src/contrib/elftoolchain/libelftc/elftc_string_table.c (revision d003e0d7fe0d3a9b4b2c5835bb3f0f6faf3ab538)
1a85fe12eSEd Maste /*-
2a85fe12eSEd Maste  * Copyright (c) 2013, Joseph Koshy
3a85fe12eSEd Maste  * All rights reserved.
4a85fe12eSEd Maste  *
5a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7a85fe12eSEd Maste  * are met:
8a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer
10a85fe12eSEd Maste  *    in this position and unchanged.
11a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
12a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
13a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
14a85fe12eSEd Maste  *
15a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16a85fe12eSEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17a85fe12eSEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18a85fe12eSEd Maste  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19a85fe12eSEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20a85fe12eSEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21a85fe12eSEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22a85fe12eSEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a85fe12eSEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24a85fe12eSEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a85fe12eSEd Maste  */
26a85fe12eSEd Maste 
27a85fe12eSEd Maste #include <sys/param.h>
28a85fe12eSEd Maste #include <sys/queue.h>
29a85fe12eSEd Maste 
30a85fe12eSEd Maste #include <assert.h>
31a85fe12eSEd Maste #include <errno.h>
32a85fe12eSEd Maste #include <gelf.h>
33a85fe12eSEd Maste #include <stdlib.h>
34a85fe12eSEd Maste #include <string.h>
35a85fe12eSEd Maste 
36a85fe12eSEd Maste #include "libelftc.h"
37a85fe12eSEd Maste #include "_libelftc.h"
38a85fe12eSEd Maste 
39*d003e0d7SEd Maste ELFTC_VCSID("$Id: elftc_string_table.c 3750 2019-06-28 01:12:10Z emaste $");
40a85fe12eSEd Maste 
41a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_DEFAULT_SIZE			(4*1024)
42a85fe12eSEd Maste #define ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE		16
43a85fe12eSEd Maste #define ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH	8
44a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT		(4*1024)
45a85fe12eSEd Maste 
46a85fe12eSEd Maste struct _Elftc_String_Table_Entry {
47b90eaf94SMark Johnston 	ssize_t		ste_idx;
48a85fe12eSEd Maste 	SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next;
49a85fe12eSEd Maste };
50a85fe12eSEd Maste 
51a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_COMPACTION_FLAG	0x1
52a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_LENGTH(st)		((st)->st_len >> 1)
53a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st) do {		\
54a85fe12eSEd Maste 		(st)->st_len &= ~ELFTC_STRING_TABLE_COMPACTION_FLAG;	\
55a85fe12eSEd Maste 	} while (0)
56a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st) do {			\
57a85fe12eSEd Maste 		(st)->st_len |= ELFTC_STRING_TABLE_COMPACTION_FLAG;	\
58a85fe12eSEd Maste 	} while (0)
59a85fe12eSEd Maste #define	ELFTC_STRING_TABLE_UPDATE_LENGTH(st, len) do {		\
60a85fe12eSEd Maste 		(st)->st_len =					\
61a85fe12eSEd Maste 		    ((st)->st_len &				\
62a85fe12eSEd Maste 			ELFTC_STRING_TABLE_COMPACTION_FLAG) |	\
63a85fe12eSEd Maste 		    ((len) << 1);				\
64a85fe12eSEd Maste 	} while (0)
65a85fe12eSEd Maste 
66a85fe12eSEd Maste struct _Elftc_String_Table {
67b90eaf94SMark Johnston 	size_t		st_len; /* length and flags */
68a85fe12eSEd Maste 	int		st_nbuckets;
69b90eaf94SMark Johnston 	size_t		st_string_pool_size;
70a85fe12eSEd Maste 	char		*st_string_pool;
71a85fe12eSEd Maste 	SLIST_HEAD(_Elftc_String_Table_Bucket,
72a85fe12eSEd Maste 	    _Elftc_String_Table_Entry) st_buckets[];
73a85fe12eSEd Maste };
74a85fe12eSEd Maste 
75a85fe12eSEd Maste static struct _Elftc_String_Table_Entry *
elftc_string_table_find_hash_entry(Elftc_String_Table * st,const char * string,int * rhashindex)76a85fe12eSEd Maste elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string,
77a85fe12eSEd Maste     int *rhashindex)
78a85fe12eSEd Maste {
79a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *ste;
80a85fe12eSEd Maste 	int hashindex;
81a85fe12eSEd Maste 	char *s;
82a85fe12eSEd Maste 
83a85fe12eSEd Maste 	hashindex = libelftc_hash_string(string) % st->st_nbuckets;
84a85fe12eSEd Maste 
85a85fe12eSEd Maste 	if (rhashindex)
86a85fe12eSEd Maste 		*rhashindex = hashindex;
87a85fe12eSEd Maste 
88a85fe12eSEd Maste 	SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) {
89b90eaf94SMark Johnston 		s = st->st_string_pool + labs(ste->ste_idx);
90a85fe12eSEd Maste 
91a85fe12eSEd Maste 		assert(s > st->st_string_pool &&
92a85fe12eSEd Maste 		    s < st->st_string_pool + st->st_string_pool_size);
93a85fe12eSEd Maste 
94a85fe12eSEd Maste 		if (strcmp(s, string) == 0)
95a85fe12eSEd Maste 			return (ste);
96a85fe12eSEd Maste 	}
97a85fe12eSEd Maste 
98a85fe12eSEd Maste 	return (NULL);
99a85fe12eSEd Maste }
100a85fe12eSEd Maste 
101a85fe12eSEd Maste static int
elftc_string_table_add_to_pool(Elftc_String_Table * st,const char * string)102a85fe12eSEd Maste elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string)
103a85fe12eSEd Maste {
104a85fe12eSEd Maste 	char *newpool;
105b90eaf94SMark Johnston 	size_t len, newsize, stlen;
106a85fe12eSEd Maste 
107a85fe12eSEd Maste 	len = strlen(string) + 1; /* length, including the trailing NUL */
108a85fe12eSEd Maste 	stlen = ELFTC_STRING_TABLE_LENGTH(st);
109a85fe12eSEd Maste 
110a85fe12eSEd Maste 	/* Resize the pool, if needed. */
111a85fe12eSEd Maste 	if (stlen + len >= st->st_string_pool_size) {
112a85fe12eSEd Maste 		newsize = roundup(st->st_string_pool_size +
113a85fe12eSEd Maste 		    ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT,
114a85fe12eSEd Maste 		    ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT);
115a85fe12eSEd Maste 		if ((newpool = realloc(st->st_string_pool, newsize)) ==
116a85fe12eSEd Maste 		    NULL)
117a85fe12eSEd Maste 			return (0);
118a85fe12eSEd Maste 		st->st_string_pool = newpool;
119a85fe12eSEd Maste 		st->st_string_pool_size = newsize;
120a85fe12eSEd Maste 	}
121a85fe12eSEd Maste 
12270b0aff9SMark Johnston 	memcpy(st->st_string_pool + stlen, string, len);
123a85fe12eSEd Maste 	ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len);
124a85fe12eSEd Maste 
125a85fe12eSEd Maste 	return (stlen);
126a85fe12eSEd Maste }
127a85fe12eSEd Maste 
128a85fe12eSEd Maste Elftc_String_Table *
elftc_string_table_create(size_t sizehint)129b90eaf94SMark Johnston elftc_string_table_create(size_t sizehint)
130a85fe12eSEd Maste {
131a85fe12eSEd Maste 	struct _Elftc_String_Table *st;
132b90eaf94SMark Johnston 	int n, nbuckets, tablesize;
133a85fe12eSEd Maste 
134a85fe12eSEd Maste 	if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE)
135a85fe12eSEd Maste 		sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE;
136a85fe12eSEd Maste 
137a85fe12eSEd Maste 	nbuckets = sizehint / (ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH *
138a85fe12eSEd Maste 	    ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE);
139a85fe12eSEd Maste 
140a85fe12eSEd Maste 	tablesize = sizeof(struct _Elftc_String_Table) +
141a85fe12eSEd Maste 	    nbuckets * sizeof(struct _Elftc_String_Table_Bucket);
142a85fe12eSEd Maste 
143a85fe12eSEd Maste 	if ((st = malloc(tablesize)) == NULL)
144a85fe12eSEd Maste 		return (NULL);
145a85fe12eSEd Maste 	if ((st->st_string_pool = malloc(sizehint)) == NULL) {
146a85fe12eSEd Maste 		free(st);
147a85fe12eSEd Maste 		return (NULL);
148a85fe12eSEd Maste 	}
149a85fe12eSEd Maste 
150a85fe12eSEd Maste 	for (n = 0; n < nbuckets; n++)
151a85fe12eSEd Maste 		SLIST_INIT(&st->st_buckets[n]);
152a85fe12eSEd Maste 
153a85fe12eSEd Maste 	st->st_len = 0;
154a85fe12eSEd Maste 	st->st_nbuckets = nbuckets;
155a85fe12eSEd Maste 	st->st_string_pool_size = sizehint;
156a85fe12eSEd Maste 	*st->st_string_pool = '\0';
157a85fe12eSEd Maste 	ELFTC_STRING_TABLE_UPDATE_LENGTH(st, 1);
158a85fe12eSEd Maste 
159a85fe12eSEd Maste 	return (st);
160a85fe12eSEd Maste }
161a85fe12eSEd Maste 
162a85fe12eSEd Maste void
elftc_string_table_destroy(Elftc_String_Table * st)163a85fe12eSEd Maste elftc_string_table_destroy(Elftc_String_Table *st)
164a85fe12eSEd Maste {
165a85fe12eSEd Maste 	int n;
166a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *s, *t;
167a85fe12eSEd Maste 
168a85fe12eSEd Maste 	for (n = 0; n < st->st_nbuckets; n++)
169a85fe12eSEd Maste 		SLIST_FOREACH_SAFE(s, &st->st_buckets[n], ste_next, t)
170a85fe12eSEd Maste 			free(s);
171a85fe12eSEd Maste 	free(st->st_string_pool);
172a85fe12eSEd Maste 	free(st);
173a85fe12eSEd Maste }
174a85fe12eSEd Maste 
175a85fe12eSEd Maste Elftc_String_Table *
elftc_string_table_from_section(Elf_Scn * scn,size_t sizehint)176b90eaf94SMark Johnston elftc_string_table_from_section(Elf_Scn *scn, size_t sizehint)
177a85fe12eSEd Maste {
178a85fe12eSEd Maste 	Elf_Data *d;
179a85fe12eSEd Maste 	GElf_Shdr sh;
180a85fe12eSEd Maste 	const char *s, *end;
181a85fe12eSEd Maste 	Elftc_String_Table *st;
182b90eaf94SMark Johnston 	size_t len;
183a85fe12eSEd Maste 
184a85fe12eSEd Maste 	/* Verify the type of the section passed in. */
185a85fe12eSEd Maste 	if (gelf_getshdr(scn, &sh) == NULL ||
186a85fe12eSEd Maste 	    sh.sh_type != SHT_STRTAB) {
187a85fe12eSEd Maste 		errno = EINVAL;
188a85fe12eSEd Maste 		return (NULL);
189a85fe12eSEd Maste 	}
190a85fe12eSEd Maste 
191a85fe12eSEd Maste 	if ((d = elf_getdata(scn, NULL)) == NULL ||
192a85fe12eSEd Maste 	    d->d_size == 0) {
193a85fe12eSEd Maste 		errno = EINVAL;
194a85fe12eSEd Maste 		return (NULL);
195a85fe12eSEd Maste 	}
196a85fe12eSEd Maste 
197a85fe12eSEd Maste 	if ((st = elftc_string_table_create(sizehint)) == NULL)
198a85fe12eSEd Maste 		return (NULL);
199a85fe12eSEd Maste 
200a85fe12eSEd Maste 	s = d->d_buf;
201a85fe12eSEd Maste 
202a85fe12eSEd Maste 	/*
203a85fe12eSEd Maste 	 * Verify that the first byte of the data buffer is '\0'.
204a85fe12eSEd Maste 	 */
205a85fe12eSEd Maste 	if (*s != '\0') {
206a85fe12eSEd Maste 		errno = EINVAL;
207a85fe12eSEd Maste 		goto fail;
208a85fe12eSEd Maste 	}
209a85fe12eSEd Maste 
210a85fe12eSEd Maste 	end = s + d->d_size;
211a85fe12eSEd Maste 
212a85fe12eSEd Maste 	/*
213a85fe12eSEd Maste 	 * Skip the first '\0' and insert the strings in the buffer,
214a85fe12eSEd Maste 	 * in order.
215a85fe12eSEd Maste 	 */
216a85fe12eSEd Maste 	for (s += 1; s < end; s += len) {
217a85fe12eSEd Maste 		if (elftc_string_table_insert(st, s) == 0)
218a85fe12eSEd Maste 			goto fail;
219a85fe12eSEd Maste 
220a85fe12eSEd Maste 		len = strlen(s) + 1; /* Include space for the trailing NUL. */
221a85fe12eSEd Maste 	}
222a85fe12eSEd Maste 
223a85fe12eSEd Maste 	return (st);
224a85fe12eSEd Maste 
225a85fe12eSEd Maste fail:
226a85fe12eSEd Maste 	if (st)
227a85fe12eSEd Maste 		(void) elftc_string_table_destroy(st);
228a85fe12eSEd Maste 
229a85fe12eSEd Maste 	return (NULL);
230a85fe12eSEd Maste }
231a85fe12eSEd Maste 
232a85fe12eSEd Maste const char *
elftc_string_table_image(Elftc_String_Table * st,size_t * size)233a85fe12eSEd Maste elftc_string_table_image(Elftc_String_Table *st, size_t *size)
234a85fe12eSEd Maste {
235a85fe12eSEd Maste 	char *r, *s, *end;
236a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *ste;
237a85fe12eSEd Maste 	struct _Elftc_String_Table_Bucket *head;
238b90eaf94SMark Johnston 	size_t copied, offset, length, newsize;
239b90eaf94SMark Johnston 	int hashindex;
240a85fe12eSEd Maste 
241a85fe12eSEd Maste 	/*
242a85fe12eSEd Maste 	 * For the common case of a string table has not seen
243a85fe12eSEd Maste 	 * a string deletion, we can just export the current
244a85fe12eSEd Maste 	 * pool.
245a85fe12eSEd Maste 	 */
246a85fe12eSEd Maste 	if ((st->st_len & ELFTC_STRING_TABLE_COMPACTION_FLAG) == 0) {
247a85fe12eSEd Maste 		if (size)
248a85fe12eSEd Maste 			*size = ELFTC_STRING_TABLE_LENGTH(st);
249a85fe12eSEd Maste 		return (st->st_string_pool);
250a85fe12eSEd Maste 	}
251a85fe12eSEd Maste 
252a85fe12eSEd Maste 	/*
253a85fe12eSEd Maste 	 * Otherwise, compact the string table in-place.
254a85fe12eSEd Maste 	 */
255a85fe12eSEd Maste 	assert(*st->st_string_pool == '\0');
256a85fe12eSEd Maste 
257a85fe12eSEd Maste 	newsize = 1;
258a85fe12eSEd Maste 	end = st->st_string_pool + ELFTC_STRING_TABLE_LENGTH(st);
259a85fe12eSEd Maste 
260a85fe12eSEd Maste 	for (r = s = st->st_string_pool + 1;
261a85fe12eSEd Maste 	     s < end;
262a85fe12eSEd Maste 	     s += length, r += copied) {
263a85fe12eSEd Maste 
264a85fe12eSEd Maste 		copied = 0;
265a85fe12eSEd Maste 		length = strlen(s) + 1;
266a85fe12eSEd Maste 
267a85fe12eSEd Maste 		ste = elftc_string_table_find_hash_entry(st, s,
268a85fe12eSEd Maste 		    &hashindex);
269a85fe12eSEd Maste 		head = &st->st_buckets[hashindex];
270a85fe12eSEd Maste 
271a85fe12eSEd Maste 		assert(ste != NULL);
272a85fe12eSEd Maste 
273a85fe12eSEd Maste 		/* Ignore deleted strings. */
274a85fe12eSEd Maste 		if (ste->ste_idx < 0) {
275a85fe12eSEd Maste 			SLIST_REMOVE(head, ste, _Elftc_String_Table_Entry,
276a85fe12eSEd Maste 			    ste_next);
277a85fe12eSEd Maste 			free(ste);
278a85fe12eSEd Maste 			continue;
279a85fe12eSEd Maste 		}
280a85fe12eSEd Maste 
281a85fe12eSEd Maste 		/* Move 'live' strings up. */
282a85fe12eSEd Maste 		offset = newsize;
283a85fe12eSEd Maste 		newsize += length;
284a85fe12eSEd Maste 		copied = length;
285a85fe12eSEd Maste 
286a85fe12eSEd Maste 		if (r == s)	/* Nothing removed yet. */
287a85fe12eSEd Maste 			continue;
288a85fe12eSEd Maste 
289a85fe12eSEd Maste 		memmove(r, s, copied);
290a85fe12eSEd Maste 
291a85fe12eSEd Maste 		/* Update the index for this entry. */
292a85fe12eSEd Maste 		ste->ste_idx = offset;
293a85fe12eSEd Maste 	}
294a85fe12eSEd Maste 
295a85fe12eSEd Maste 	ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st);
296a85fe12eSEd Maste 	ELFTC_STRING_TABLE_UPDATE_LENGTH(st, newsize);
297a85fe12eSEd Maste 
298a85fe12eSEd Maste 	if (size)
299a85fe12eSEd Maste 		*size = newsize;
300a85fe12eSEd Maste 
301a85fe12eSEd Maste 	return (st->st_string_pool);
302a85fe12eSEd Maste }
303a85fe12eSEd Maste 
304a85fe12eSEd Maste size_t
elftc_string_table_insert(Elftc_String_Table * st,const char * string)305a85fe12eSEd Maste elftc_string_table_insert(Elftc_String_Table *st, const char *string)
306a85fe12eSEd Maste {
307a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *ste;
308b90eaf94SMark Johnston 	ssize_t idx;
309b90eaf94SMark Johnston 	int hashindex;
310a85fe12eSEd Maste 
311a85fe12eSEd Maste 	hashindex = 0;
312a85fe12eSEd Maste 
313a85fe12eSEd Maste 	ste = elftc_string_table_find_hash_entry(st, string, &hashindex);
314a85fe12eSEd Maste 
315a85fe12eSEd Maste 	assert(hashindex >= 0 && hashindex < st->st_nbuckets);
316a85fe12eSEd Maste 
317a85fe12eSEd Maste 	if (ste == NULL) {
318a85fe12eSEd Maste 		if ((ste = malloc(sizeof(*ste))) == NULL)
319a85fe12eSEd Maste 			return (0);
320a85fe12eSEd Maste 		if ((ste->ste_idx = elftc_string_table_add_to_pool(st,
321a85fe12eSEd Maste 		    string)) == 0) {
322a85fe12eSEd Maste 			free(ste);
323a85fe12eSEd Maste 			return (0);
324a85fe12eSEd Maste 		}
325a85fe12eSEd Maste 
326a85fe12eSEd Maste 		SLIST_INSERT_HEAD(&st->st_buckets[hashindex], ste, ste_next);
327a85fe12eSEd Maste 	}
328a85fe12eSEd Maste 
329a85fe12eSEd Maste 	idx = ste->ste_idx;
330a85fe12eSEd Maste 	if (idx < 0) 		/* Undelete. */
331b90eaf94SMark Johnston 		ste->ste_idx = idx = -idx;
332a85fe12eSEd Maste 
333a85fe12eSEd Maste 	return (idx);
334a85fe12eSEd Maste }
335a85fe12eSEd Maste 
336a85fe12eSEd Maste size_t
elftc_string_table_lookup(Elftc_String_Table * st,const char * string)337a85fe12eSEd Maste elftc_string_table_lookup(Elftc_String_Table *st, const char *string)
338a85fe12eSEd Maste {
339a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *ste;
340b90eaf94SMark Johnston 	ssize_t idx;
341b90eaf94SMark Johnston 	int hashindex;
342a85fe12eSEd Maste 
343a85fe12eSEd Maste 	ste = elftc_string_table_find_hash_entry(st, string, &hashindex);
344a85fe12eSEd Maste 
345a85fe12eSEd Maste 	assert(hashindex >= 0 && hashindex < st->st_nbuckets);
346a85fe12eSEd Maste 
347a85fe12eSEd Maste 	if (ste == NULL || (idx = ste->ste_idx) < 0)
348a85fe12eSEd Maste 		return (0);
349a85fe12eSEd Maste 
350a85fe12eSEd Maste 	return (idx);
351a85fe12eSEd Maste }
352a85fe12eSEd Maste 
353a85fe12eSEd Maste int
elftc_string_table_remove(Elftc_String_Table * st,const char * string)354a85fe12eSEd Maste elftc_string_table_remove(Elftc_String_Table *st, const char *string)
355a85fe12eSEd Maste {
356a85fe12eSEd Maste 	struct _Elftc_String_Table_Entry *ste;
357b90eaf94SMark Johnston 	ssize_t idx;
358a85fe12eSEd Maste 
359a85fe12eSEd Maste 	ste = elftc_string_table_find_hash_entry(st, string, NULL);
360a85fe12eSEd Maste 
361a85fe12eSEd Maste 	if (ste == NULL || (idx = ste->ste_idx) < 0)
362a85fe12eSEd Maste 		return (ELFTC_FAILURE);
363a85fe12eSEd Maste 
364b90eaf94SMark Johnston 	assert(idx > 0 && (size_t)idx < ELFTC_STRING_TABLE_LENGTH(st));
365a85fe12eSEd Maste 
366b90eaf94SMark Johnston 	ste->ste_idx = -idx;
367a85fe12eSEd Maste 
368a85fe12eSEd Maste 	ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st);
369a85fe12eSEd Maste 
370a85fe12eSEd Maste 	return (ELFTC_SUCCESS);
371a85fe12eSEd Maste }
372a85fe12eSEd Maste 
373a85fe12eSEd Maste const char *
elftc_string_table_to_string(Elftc_String_Table * st,size_t offset)374a85fe12eSEd Maste elftc_string_table_to_string(Elftc_String_Table *st, size_t offset)
375a85fe12eSEd Maste {
376a85fe12eSEd Maste 	const char *s;
377a85fe12eSEd Maste 
378a85fe12eSEd Maste 	s = st->st_string_pool + offset;
379a85fe12eSEd Maste 
380a85fe12eSEd Maste 	/*
381a85fe12eSEd Maste 	 * Check for:
382a85fe12eSEd Maste 	 * - An offset value within pool bounds.
383a85fe12eSEd Maste 	 * - A non-NUL byte at the specified offset.
384a85fe12eSEd Maste 	 * - The end of the prior string at offset - 1.
385a85fe12eSEd Maste 	 */
386a85fe12eSEd Maste 	if (offset == 0 || offset >= ELFTC_STRING_TABLE_LENGTH(st) ||
387a85fe12eSEd Maste 	    *s == '\0' || *(s - 1) != '\0') {
388a85fe12eSEd Maste 		errno = EINVAL;
389a85fe12eSEd Maste 		return (NULL);
390a85fe12eSEd Maste 	}
391a85fe12eSEd Maste 
392a85fe12eSEd Maste 	return (s);
393a85fe12eSEd Maste }
394