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