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