xref: /illumos-gate/usr/src/common/elfcap/elfcap.c (revision d51e90740114c60620c0febffd4d3ce6e280a107)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 /* LINTLIBRARY */
28 
29 /*
30  * String conversion routine for hardware capabilities types.
31  */
32 #include	<strings.h>
33 #include	<stdio.h>
34 #include	<ctype.h>
35 #include	<limits.h>
36 #include	<sys/machelf.h>
37 #include	<sys/elf.h>
38 #include	<sys/auxv_SPARC.h>
39 #include	<sys/auxv_386.h>
40 #include	<elfcap.h>
41 
42 /*
43  * Define separators for val2str processing.
44  */
45 static const Fmt_desc format[] = {
46 	{" ",	1 },
47 	{"  ",	2 },
48 	{" | ",	3 }
49 };
50 
51 /*
52  * Define all known capabilities as both lower and upper case strings.  This
53  * duplication is necessary, rather than have one string and use something
54  * like toupper(), as a client such as ld.so.1 doesn't need the overhead of
55  * dragging in the internationalization support of toupper().  The Intel 3DNow
56  * flags are a slightly odd convention too.
57  *
58  * Define all known software capabilities.
59  */
60 #ifdef	CAP_UPPERCASE
61 static const char Sf1_fpknwn[] =	"FPKNWN";
62 static const char Sf1_fpused[] =	"FPUSED";
63 #elif	CAP_LOWERCASE
64 static const char Sf1_fpknwn[] =	"fpknwn";
65 static const char Sf1_fpused[] =	"fpused";
66 #else
67 #error	"Software Capabilities - what case do you want?"
68 #endif
69 
70 /*
71  * Order the software capabilities to match their numeric value.  See SF1_SUNW_
72  * values in sys/elf.h.
73  */
74 static const Cap_desc sf1[] = {
75 	{ SF1_SUNW_FPKNWN,	Sf1_fpknwn,	(sizeof (Sf1_fpknwn) - 1) },
76 	{ SF1_SUNW_FPUSED,	Sf1_fpused,	(sizeof (Sf1_fpused) - 1) }
77 };
78 static const uint_t sf1_num = sizeof (sf1) / sizeof (Cap_desc);
79 
80 /*
81  * Define all known SPARC hardware capabilities.
82  */
83 #ifdef	CAP_UPPERCASE
84 static const char Hw1_s_mul32[] =	"MUL32";
85 static const char Hw1_s_div32[] =	"DIV32";
86 static const char Hw1_s_fsmuld[] =	"FSMULD";
87 static const char Hw1_s_v8plus[] =	"V8PLUS";
88 static const char Hw1_s_popc[] =	"POPC";
89 static const char Hw1_s_vis[] =		"VIS";
90 static const char Hw1_s_vis2[] =	"VIS2";
91 static const char Hw1_s_asi_blk_init[] =	"ASI_BLK_INIT";
92 static const char Hw1_s_fmaf[] = 	"FMAF";
93 #elif	CAP_LOWERCASE
94 static const char Hw1_s_mul32[] =	"mul32";
95 static const char Hw1_s_div32[] =	"div32";
96 static const char Hw1_s_fsmuld[] =	"fsmuld";
97 static const char Hw1_s_v8plus[] =	"v8plus";
98 static const char Hw1_s_popc[] =	"popc";
99 static const char Hw1_s_vis[] =		"vis";
100 static const char Hw1_s_vis2[] =	"vis2";
101 static const char Hw1_s_asi_blk_init[] =	"asi_blk_init";
102 static const char Hw1_s_fmaf[] =	"fmaf";
103 
104 #else
105 #error	"Hardware Capabilities (sparc) - what case do you want?"
106 #endif
107 
108 /*
109  * Order the SPARC hardware capabilities to match their numeric value.  See
110  * AV_SPARC_ values in sys/auxv_SPARC.h.
111  */
112 static const Cap_desc hw1_s[] = {
113 	{ AV_SPARC_MUL32,	Hw1_s_mul32,	sizeof (Hw1_s_mul32) - 1 },
114 	{ AV_SPARC_DIV32,	Hw1_s_div32,	sizeof (Hw1_s_div32) - 1 },
115 	{ AV_SPARC_FSMULD,	Hw1_s_fsmuld,	sizeof (Hw1_s_fsmuld) - 1 },
116 	{ AV_SPARC_V8PLUS,	Hw1_s_v8plus,	sizeof (Hw1_s_v8plus) - 1 },
117 	{ AV_SPARC_POPC,	Hw1_s_popc,	sizeof (Hw1_s_popc) - 1 },
118 	{ AV_SPARC_VIS,		Hw1_s_vis,	sizeof (Hw1_s_vis) - 1 },
119 	{ AV_SPARC_VIS2,	Hw1_s_vis2,	sizeof (Hw1_s_vis2) - 1 },
120 	{ AV_SPARC_ASI_BLK_INIT,	Hw1_s_asi_blk_init,
121 		sizeof (Hw1_s_asi_blk_init) - 1 },
122 	{ AV_SPARC_FMAF,	Hw1_s_fmaf,	sizeof (Hw1_s_fmaf) - 1 }
123 };
124 static const uint_t hw1_s_num = sizeof (hw1_s) / sizeof (Cap_desc);
125 
126 /*
127  * Define all known Intel hardware capabilities.
128  */
129 #ifdef	CAP_UPPERCASE
130 static const char Hw1_i_fpu[] =		"FPU";
131 static const char Hw1_i_tsc[] =		"TSC";
132 static const char Hw1_i_cx8[] =		"CX8";
133 static const char Hw1_i_sep[] =		"SEP";
134 static const char Hw1_i_amd_sysc[] =	"AMD_SYSC";
135 static const char Hw1_i_cmov[] =	"CMOV";
136 static const char Hw1_i_mmx[] =		"MMX";
137 static const char Hw1_i_amd_mmx[] =	"AMD_MMX";
138 static const char Hw1_i_amd_3dnow[] =	"AMD_3DNow";
139 static const char Hw1_i_amd_3dnowx[] =	"AMD_3DNowx";
140 static const char Hw1_i_fxsr[] =	"FXSR";
141 static const char Hw1_i_sse[] =		"SSE";
142 static const char Hw1_i_sse2[] =	"SSE2";
143 static const char Hw1_i_pause[] =	"PAUSE";
144 static const char Hw1_i_sse3[] =	"SSE3";
145 static const char Hw1_i_mon[] =		"MON";
146 static const char Hw1_i_cx16[] =	"CX16";
147 #elif	CAP_LOWERCASE
148 static const char Hw1_i_fpu[] =		"fpu";
149 static const char Hw1_i_tsc[] =		"tsc";
150 static const char Hw1_i_cx8[] =		"cx8";
151 static const char Hw1_i_sep[] =		"sep";
152 static const char Hw1_i_amd_sysc[] =	"amd_sysc";
153 static const char Hw1_i_cmov[] =	"cmov";
154 static const char Hw1_i_mmx[] =		"mmx";
155 static const char Hw1_i_amd_mmx[] =	"amd_mmx";
156 static const char Hw1_i_amd_3dnow[] =	"amd_3dnow";
157 static const char Hw1_i_amd_3dnowx[] =	"amd_3dnowx";
158 static const char Hw1_i_fxsr[] =	"fxsr";
159 static const char Hw1_i_sse[] =		"sse";
160 static const char Hw1_i_sse2[] =	"sse2";
161 static const char Hw1_i_pause[] =	"pause";
162 static const char Hw1_i_sse3[] =	"sse3";
163 static const char Hw1_i_mon[] =		"mon";
164 static const char Hw1_i_cx16[] =	"cx16";
165 #else
166 #error	"Hardware Capabilities (intel) - what case do you want?"
167 #endif
168 
169 /*
170  * Order the Intel hardware capabilities to match their numeric value.  See
171  * AV_386_ values in sys/auxv_386.h.
172  */
173 static const Cap_desc hw1_i[] = {
174 	{ AV_386_FPU,		Hw1_i_fpu,	sizeof (Hw1_i_fpu) - 1 },
175 	{ AV_386_TSC,		Hw1_i_tsc,	sizeof (Hw1_i_tsc) - 1 },
176 	{ AV_386_CX8,		Hw1_i_cx8,	sizeof (Hw1_i_cx8) - 1 },
177 	{ AV_386_SEP,		Hw1_i_sep,	sizeof (Hw1_i_sep) - 1 },
178 	{ AV_386_AMD_SYSC,	Hw1_i_amd_sysc,	sizeof (Hw1_i_amd_sysc) - 1 },
179 	{ AV_386_CMOV,		Hw1_i_cmov,	sizeof (Hw1_i_cmov) - 1 },
180 	{ AV_386_MMX,		Hw1_i_mmx,	sizeof (Hw1_i_mmx) - 1 },
181 	{ AV_386_AMD_MMX,	Hw1_i_amd_mmx,	sizeof (Hw1_i_amd_mmx) - 1 },
182 	{ AV_386_AMD_3DNow,	Hw1_i_amd_3dnow,
183 						sizeof (Hw1_i_amd_3dnow) - 1 },
184 	{ AV_386_AMD_3DNowx,	Hw1_i_amd_3dnowx,
185 						sizeof (Hw1_i_amd_3dnowx) - 1 },
186 	{ AV_386_FXSR,		Hw1_i_fxsr,	sizeof (Hw1_i_fxsr) - 1 },
187 	{ AV_386_SSE,		Hw1_i_sse,	sizeof (Hw1_i_sse) - 1 },
188 	{ AV_386_SSE2,		Hw1_i_sse2,	sizeof (Hw1_i_sse2) - 1 },
189 	{ AV_386_PAUSE,		Hw1_i_pause,	sizeof (Hw1_i_pause) - 1 },
190 	{ AV_386_SSE3,		Hw1_i_sse3,	sizeof (Hw1_i_sse3) - 1 },
191 	{ AV_386_MON,		Hw1_i_mon,	sizeof (Hw1_i_mon) - 1 },
192 	{ AV_386_CX16,		Hw1_i_cx16,	sizeof (Hw1_i_cx16) - 1 }
193 };
194 static const uint_t hw1_i_num = sizeof (hw1_i) / sizeof (Cap_desc);
195 
196 /*
197  * Concatenate a token to the string buffer.  This can be a capailities token
198  * or a separator token.
199  */
200 static int
201 token(char **ostr, size_t *olen, const char *nstr, size_t nlen)
202 {
203 	if (*olen < nlen)
204 		return (CAP_ERR_BUFOVFL);
205 
206 	(void) strcat(*ostr, nstr);
207 	*ostr += nlen;
208 	*olen -= nlen;
209 
210 	return (0);
211 }
212 
213 /*
214  * Expand a capabilities value into the strings defined in the associated
215  * capabilities descriptor.
216  */
217 static int
218 expand(uint64_t val, const Cap_desc *cdp, uint_t cnum, char *str, size_t slen,
219     int fmt)
220 {
221 	uint_t	cnt, mask;
222 	int	follow = 0, err;
223 
224 	if (val == 0)
225 		return (0);
226 
227 	for (cnt = WORD_BIT, mask = 0x80000000; cnt; cnt--,
228 	    (mask = mask >> 1)) {
229 		if ((val & mask) && (cnt <= cnum) && cdp[cnt - 1].c_val) {
230 			if (follow++ && ((err = token(&str, &slen,
231 			    format[fmt].f_str, format[fmt].f_len)) != 0))
232 				return (err);
233 
234 			if ((err = token(&str, &slen, cdp[cnt - 1].c_str,
235 			    cdp[cnt - 1].c_len)) != 0)
236 				return (err);
237 
238 			val = val & ~mask;
239 		}
240 	}
241 
242 	/*
243 	 * If there are any unknown bits remaining display the numeric value.
244 	 */
245 	if (val) {
246 		if (follow && ((err = token(&str, &slen, format[fmt].f_str,
247 		    format[fmt].f_len)) != 0))
248 			return (err);
249 
250 		(void) snprintf(str, slen, "0x%llx", val);
251 	}
252 	return (0);
253 }
254 
255 /*
256  * Expand a CA_SUNW_HW_1 value.
257  */
258 int
259 hwcap_1_val2str(uint64_t val, char *str, size_t len, int fmt, ushort_t mach)
260 {
261 	/*
262 	 * Initialize the string buffer, and validate the format request.
263 	 */
264 	*str = '\0';
265 	if (fmt > CAP_MAX_TYPE)
266 		return (CAP_ERR_INVFMT);
267 
268 	if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
269 		return (expand(val, &hw1_i[0], hw1_i_num, str, len, fmt));
270 
271 	if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
272 	    (mach == EM_SPARCV9))
273 		return (expand(val, &hw1_s[0], hw1_s_num, str, len, fmt));
274 
275 	return (CAP_ERR_UNKMACH);
276 }
277 
278 /*
279  * Expand a CA_SUNW_SF_1 value.  Note, that at present these capabilities are
280  * common across all platforms.  The use of "mach" is therefore redundant, but
281  * is retained for compatibility with the interface of hwcap_1_val2str(), and
282  * possible future expansion.
283  */
284 int
285 /* ARGSUSED4 */
286 sfcap_1_val2str(uint64_t val, char *str, size_t len, int fmt, ushort_t mach)
287 {
288 	/*
289 	 * Initialize the string buffer, and validate the format request.
290 	 */
291 	*str = '\0';
292 	if (fmt > CAP_MAX_TYPE)
293 		return (CAP_ERR_INVFMT);
294 
295 	return (expand(val, &sf1[0], sf1_num, str, len, fmt));
296 }
297 
298 /*
299  * Determine capability type from the capability tag.
300  */
301 int
302 cap_val2str(uint64_t tag, uint64_t val, char *str, size_t len, int fmt,
303     ushort_t mach)
304 {
305 	if (tag == CA_SUNW_HW_1)
306 		return (hwcap_1_val2str(val, str, len, fmt, mach));
307 	if (tag == CA_SUNW_SF_1)
308 		return (sfcap_1_val2str(val, str, len, fmt, mach));
309 
310 	return (CAP_ERR_UNKTAG);
311 }
312 
313 /*
314  * Determine a capabilities value from a capabilities string.
315  */
316 static uint64_t
317 value(const char *str, const Cap_desc *cdp, uint_t cnum)
318 {
319 	uint_t	num;
320 
321 	for (num = 0; num < cnum; num++) {
322 		if (strcmp(str, cdp[num].c_str) == 0)
323 			return (cdp[num].c_val);
324 	}
325 	return (0);
326 }
327 
328 uint64_t
329 sfcap_1_str2val(const char *str, ushort_t mach)
330 {
331 	return (value(str, &sf1[0], sf1_num));
332 }
333 
334 uint64_t
335 hwcap_1_str2val(const char *str, ushort_t mach)
336 {
337 	if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
338 		return (value(str, &hw1_i[0], hw1_i_num));
339 
340 	if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
341 	    (mach == EM_SPARCV9))
342 		return (value(str, &hw1_s[0], hw1_s_num));
343 
344 	return (0);
345 }
346