1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  14  * Use is subject to license terms.
  15  */
  16 
  17 /*
  18  * Copyright 2021 Oxide Computer Company
  19  */
  20 
  21 #ifndef _KERNEL
  22 #include <stdlib.h>
  23 #include <strings.h>
  24 #include <stddef.h>
  25 #else
  26 #include <sys/types.h>
  27 #include <sys/kmem.h>
  28 #include <sys/ddi.h>
  29 #include <sys/sunddi.h>
  30 #include <sys/stddef.h>
  31 #endif  /* _KERNEL */
  32 
  33 #include <core_shstrtab.h>
  34 
  35 const char *shstrtab_data[STR_NUM] = {
  36         "",
  37         ".SUNW_ctf",
  38         ".symtab",
  39         ".dynsym",
  40         ".strtab",
  41         ".dynstr",
  42         ".shstrtab"
  43 };
  44 
  45 static void *
  46 shstrtab_alloc(void)
  47 {
  48 #ifdef  _KERNEL
  49         return (kmem_zalloc(sizeof (shstrtab_ent_t),
  50             KM_NOSLEEP | KM_NORMALPRI));
  51 #else
  52         return (calloc(1, sizeof (shstrtab_ent_t)));
  53 #endif
  54 }
  55 
  56 static void
  57 shstrtab_free(shstrtab_ent_t *ent)
  58 {
  59 #ifdef  _KERNEL
  60         if (ent->sste_name != NULL) {
  61                 strfree(ent->sste_name);
  62         }
  63         kmem_free(ent, sizeof (*ent));
  64 #else
  65         free(ent->sste_name);
  66         free(ent);
  67 #endif
  68 }
  69 
  70 
  71 boolean_t
  72 shstrtab_ndx(shstrtab_t *s, const char *name, Elf32_Word *offp)
  73 {
  74         shstrtab_ent_t *ent;
  75 
  76         for (ent = list_head(&s->sst_names); ent != NULL;
  77             ent = list_next(&s->sst_names, ent)) {
  78                 if (strcmp(name, ent->sste_name) == 0) {
  79                         if (offp != NULL)
  80                                 *offp = ent->sste_offset;
  81                         return (B_TRUE);
  82                 }
  83         }
  84 
  85         ent = shstrtab_alloc();
  86         if (ent == NULL) {
  87                 return (B_FALSE);
  88         }
  89 
  90         ent->sste_name = strdup(name);
  91         if (ent->sste_name == NULL) {
  92                 shstrtab_free(ent);
  93                 return (B_FALSE);
  94         }
  95         ent->sste_len = strlen(name) + 1;
  96         ent->sste_offset = s->sst_len;
  97         s->sst_len += ent->sste_len;
  98 
  99         list_insert_tail(&s->sst_names, ent);
 100 
 101         if (offp != NULL)
 102                 *offp = ent->sste_offset;
 103         return (B_TRUE);
 104 }
 105 
 106 boolean_t
 107 shstrtab_init(shstrtab_t *s)
 108 {
 109         bzero(s, sizeof (*s));
 110         list_create(&s->sst_names, sizeof (shstrtab_ent_t),
 111             offsetof(shstrtab_ent_t, sste_link));
 112 
 113         return (shstrtab_ndx(s, shstrtab_data[STR_NONE], NULL));
 114 }
 115 
 116 void
 117 shstrtab_fini(shstrtab_t *s)
 118 {
 119         shstrtab_ent_t *ent;
 120 
 121         if (s->sst_len == 0)
 122                 return;
 123 
 124         while ((ent = list_remove_head(&s->sst_names)) != NULL) {
 125                 shstrtab_free(ent);
 126         }
 127 }
 128 
 129 size_t
 130 shstrtab_size(const shstrtab_t *s)
 131 {
 132         return (s->sst_len);
 133 }
 134 
 135 void
 136 shstrtab_dump(shstrtab_t *s, void *buf)
 137 {
 138         size_t off = 0;
 139 
 140         for (shstrtab_ent_t *ent = list_head(&s->sst_names); ent != NULL;
 141             ent = list_next(&s->sst_names, ent)) {
 142                 bcopy(ent->sste_name, buf + off, ent->sste_len);
 143                 off += ent->sste_len;
 144         }
 145 }