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 *
shstrtab_alloc(void)46 shstrtab_alloc(void)
47 {
48 #ifdef	_KERNEL
49 	return (kmem_zalloc(sizeof (shstrtab_ent_t), KM_NOSLEEP_LAZY));
50 #else
51 	return (calloc(1, sizeof (shstrtab_ent_t)));
52 #endif
53 }
54 
55 static void
shstrtab_free(shstrtab_ent_t * ent)56 shstrtab_free(shstrtab_ent_t *ent)
57 {
58 #ifdef	_KERNEL
59 	if (ent->sste_name != NULL) {
60 		strfree(ent->sste_name);
61 	}
62 	kmem_free(ent, sizeof (*ent));
63 #else
64 	free(ent->sste_name);
65 	free(ent);
66 #endif
67 }
68 
69 
70 boolean_t
shstrtab_ndx(shstrtab_t * s,const char * name,Elf32_Word * offp)71 shstrtab_ndx(shstrtab_t *s, const char *name, Elf32_Word *offp)
72 {
73 	shstrtab_ent_t *ent;
74 
75 	for (ent = list_head(&s->sst_names); ent != NULL;
76 	    ent = list_next(&s->sst_names, ent)) {
77 		if (strcmp(name, ent->sste_name) == 0) {
78 			if (offp != NULL)
79 				*offp = ent->sste_offset;
80 			return (B_TRUE);
81 		}
82 	}
83 
84 	ent = shstrtab_alloc();
85 	if (ent == NULL) {
86 		return (B_FALSE);
87 	}
88 
89 	ent->sste_name = strdup(name);
90 	if (ent->sste_name == NULL) {
91 		shstrtab_free(ent);
92 		return (B_FALSE);
93 	}
94 	ent->sste_len = strlen(name) + 1;
95 	ent->sste_offset = s->sst_len;
96 	s->sst_len += ent->sste_len;
97 
98 	list_insert_tail(&s->sst_names, ent);
99 
100 	if (offp != NULL)
101 		*offp = ent->sste_offset;
102 	return (B_TRUE);
103 }
104 
105 boolean_t
shstrtab_init(shstrtab_t * s)106 shstrtab_init(shstrtab_t *s)
107 {
108 	bzero(s, sizeof (*s));
109 	list_create(&s->sst_names, sizeof (shstrtab_ent_t),
110 	    offsetof(shstrtab_ent_t, sste_link));
111 
112 	return (shstrtab_ndx(s, shstrtab_data[STR_NONE], NULL));
113 }
114 
115 void
shstrtab_fini(shstrtab_t * s)116 shstrtab_fini(shstrtab_t *s)
117 {
118 	shstrtab_ent_t *ent;
119 
120 	if (s->sst_len == 0)
121 		return;
122 
123 	while ((ent = list_remove_head(&s->sst_names)) != NULL) {
124 		shstrtab_free(ent);
125 	}
126 }
127 
128 size_t
shstrtab_size(const shstrtab_t * s)129 shstrtab_size(const shstrtab_t *s)
130 {
131 	return (s->sst_len);
132 }
133 
134 void
shstrtab_dump(shstrtab_t * s,void * buf)135 shstrtab_dump(shstrtab_t *s, void *buf)
136 {
137 	size_t off = 0;
138 
139 	for (shstrtab_ent_t *ent = list_head(&s->sst_names); ent != NULL;
140 	    ent = list_next(&s->sst_names, ent)) {
141 		bcopy(ent->sste_name, buf + off, ent->sste_len);
142 		off += ent->sste_len;
143 	}
144 }
145