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 /*
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2019, Joyent, Inc.
25 * Copyright 2022 Oxide Computer Company
26 */
27
28 /* LINTLIBRARY */
29
30 /*
31 * String conversion routine for hardware capabilities types.
32 */
33 #include <strings.h>
34 #include <stdio.h>
35 #include <ctype.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 * Given a literal string, generate an initialization for an
44 * elfcap_str_t value.
45 */
46 #define STRDESC(_str) { _str, sizeof (_str) - 1 }
47
48 /*
49 * The items in the elfcap_desc_t arrays are required to be
50 * ordered so that the array index is related to the
51 * c_val field as:
52 *
53 * array[ndx].c_val = 2^ndx
54 *
55 * meaning that
56 *
57 * array[0].c_val = 2^0 = 1
58 * array[1].c_val = 2^1 = 2
59 * array[2].c_val = 2^2 = 4
60 * .
61 * .
62 * .
63 *
64 * Since 0 is not a valid value for the c_val field, we use it to
65 * mark an array entry that is a placeholder. This can happen if there
66 * is a hole in the assigned bits.
67 *
68 * The RESERVED_ELFCAP_DESC macro is used to reserve such holes.
69 */
70 #define RESERVED_ELFCAP_DESC { 0, { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }
71
72 /*
73 * Define separators for output string processing. This must be kept in
74 * sync with the elfcap_fmt_t values in elfcap.h. If something is added here
75 * that is longer than ELFCAP_FMT_PIPSPACE, please update elfcap_chk.c.
76 */
77 static const elfcap_str_t format[] = {
78 STRDESC(" "), /* ELFCAP_FMT_SNGSPACE */
79 STRDESC(" "), /* ELFCAP_FMT_DBLSPACE */
80 STRDESC(" | ") /* ELFCAP_FMT_PIPSPACE */
81 };
82 #define FORMAT_NELTS (sizeof (format) / sizeof (format[0]))
83
84
85
86 /*
87 * Define all known software capabilities in all the supported styles.
88 * Order the capabilities by their numeric value. See SF1_SUNW_
89 * values in sys/elf.h.
90 */
91 static const elfcap_desc_t sf1[ELFCAP_NUM_SF1] = {
92 { /* 0x00000001 */
93 SF1_SUNW_FPKNWN, STRDESC("SF1_SUNW_FPKNWN"),
94 STRDESC("FPKNWN"), STRDESC("fpknwn")
95 },
96 { /* 0x00000002 */
97 SF1_SUNW_FPUSED, STRDESC("SF1_SUNW_FPUSED"),
98 STRDESC("FPUSED"), STRDESC("fpused"),
99 },
100 { /* 0x00000004 */
101 SF1_SUNW_ADDR32, STRDESC("SF1_SUNW_ADDR32"),
102 STRDESC("ADDR32"), STRDESC("addr32"),
103 }
104 };
105
106
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 elfcap_desc_t hw1_sparc[ELFCAP_NUM_HW1_SPARC] = {
113 { /* 0x00000001 */
114 AV_SPARC_MUL32, STRDESC("AV_SPARC_MUL32"),
115 STRDESC("MUL32"), STRDESC("mul32"),
116 },
117 { /* 0x00000002 */
118 AV_SPARC_DIV32, STRDESC("AV_SPARC_DIV32"),
119 STRDESC("DIV32"), STRDESC("div32"),
120 },
121 { /* 0x00000004 */
122 AV_SPARC_FSMULD, STRDESC("AV_SPARC_FSMULD"),
123 STRDESC("FSMULD"), STRDESC("fsmuld"),
124 },
125 { /* 0x00000008 */
126 AV_SPARC_V8PLUS, STRDESC("AV_SPARC_V8PLUS"),
127 STRDESC("V8PLUS"), STRDESC("v8plus"),
128 },
129 { /* 0x00000010 */
130 AV_SPARC_POPC, STRDESC("AV_SPARC_POPC"),
131 STRDESC("POPC"), STRDESC("popc"),
132 },
133 { /* 0x00000020 */
134 AV_SPARC_VIS, STRDESC("AV_SPARC_VIS"),
135 STRDESC("VIS"), STRDESC("vis"),
136 },
137 { /* 0x00000040 */
138 AV_SPARC_VIS2, STRDESC("AV_SPARC_VIS2"),
139 STRDESC("VIS2"), STRDESC("vis2"),
140 },
141 { /* 0x00000080 */
142 AV_SPARC_ASI_BLK_INIT, STRDESC("AV_SPARC_ASI_BLK_INIT"),
143 STRDESC("ASI_BLK_INIT"), STRDESC("asi_blk_init"),
144 },
145 { /* 0x00000100 */
146 AV_SPARC_FMAF, STRDESC("AV_SPARC_FMAF"),
147 STRDESC("FMAF"), STRDESC("fmaf"),
148 },
149 RESERVED_ELFCAP_DESC, /* 0x00000200 */
150 { /* 0x00000400 */
151 AV_SPARC_VIS3, STRDESC("AV_SPARC_VIS3"),
152 STRDESC("VIS3"), STRDESC("vis3"),
153 },
154 { /* 0x00000800 */
155 AV_SPARC_HPC, STRDESC("AV_SPARC_HPC"),
156 STRDESC("HPC"), STRDESC("hpc"),
157 },
158 { /* 0x00001000 */
159 AV_SPARC_RANDOM, STRDESC("AV_SPARC_RANDOM"),
160 STRDESC("RANDOM"), STRDESC("random"),
161 },
162 { /* 0x00002000 */
163 AV_SPARC_TRANS, STRDESC("AV_SPARC_TRANS"),
164 STRDESC("TRANS"), STRDESC("trans"),
165 },
166 { /* 0x00004000 */
167 AV_SPARC_FJFMAU, STRDESC("AV_SPARC_FJFMAU"),
168 STRDESC("FJFMAU"), STRDESC("fjfmau"),
169 },
170 { /* 0x00008000 */
171 AV_SPARC_IMA, STRDESC("AV_SPARC_IMA"),
172 STRDESC("IMA"), STRDESC("ima"),
173 },
174 { /* 0x00010000 */
175 AV_SPARC_ASI_CACHE_SPARING,
176 STRDESC("AV_SPARC_ASI_CACHE_SPARING"),
177 STRDESC("CSPARE"), STRDESC("cspare"),
178 },
179 { /* 0x00020000 */
180 AV_SPARC_PAUSE,
181 STRDESC("AV_SPARC_PAUSE"),
182 STRDESC("PAUSE"), STRDESC("pause"),
183 },
184 { /* 0x00040000 */
185 AV_SPARC_CBCOND,
186 STRDESC("AV_SPARC_CBCOND"),
187 STRDESC("CBCOND"), STRDESC("cbcond"),
188 },
189 { /* 0x00080000 */
190 AV_SPARC_AES,
191 STRDESC("AV_SPARC_AES"),
192 STRDESC("AES"), STRDESC("aes"),
193 },
194 { /* 0x00100000 */
195 AV_SPARC_DES,
196 STRDESC("AV_SPARC_DES"),
197 STRDESC("DES"), STRDESC("des"),
198 },
199 { /* 0x00200000 */
200 AV_SPARC_KASUMI,
201 STRDESC("AV_SPARC_KASUMI"),
202 STRDESC("KASUMI"), STRDESC("kasumi"),
203 },
204 { /* 0x00400000 */
205 AV_SPARC_CAMELLIA,
206 STRDESC("AV_SPARC_CAMELLIA"),
207 STRDESC("CAMELLIA"), STRDESC("camellia"),
208 },
209 { /* 0x00800000 */
210 AV_SPARC_MD5,
211 STRDESC("AV_SPARC_MD5"),
212 STRDESC("MD5"), STRDESC("md5"),
213 },
214 { /* 0x01000000 */
215 AV_SPARC_SHA1,
216 STRDESC("AV_SPARC_SHA1"),
217 STRDESC("SHA1"), STRDESC("sha1"),
218 },
219 { /* 0x02000000 */
220 AV_SPARC_SHA256,
221 STRDESC("AV_SPARC_SHA256"),
222 STRDESC("SHA256"), STRDESC("sha256"),
223 },
224 { /* 0x04000000 */
225 AV_SPARC_SHA512,
226 STRDESC("AV_SPARC_SHA512"),
227 STRDESC("SHA512"), STRDESC("sha512"),
228 },
229 { /* 0x08000000 */
230 AV_SPARC_MPMUL,
231 STRDESC("AV_SPARC_MPMUL"),
232 STRDESC("MPMUL"), STRDESC("mpmul"),
233 },
234 { /* 0x10000000 */
235 AV_SPARC_MONT,
236 STRDESC("AV_SPARC_MONT"),
237 STRDESC("MONT"), STRDESC("mont"),
238 },
239 { /* 0x20000000 */
240 AV_SPARC_CRC32C,
241 STRDESC("AV_SPARC_CRC32C"),
242 STRDESC("CRC32C"), STRDESC("crc32c"),
243 }
244 };
245
246
247
248 /*
249 * Order the Intel hardware capabilities to match their numeric value. See
250 * AV_386_ values in sys/auxv_386.h.
251 */
252 static const elfcap_desc_t hw1_386[ELFCAP_NUM_HW1_386] = {
253 { /* 0x00000001 */
254 AV_386_FPU, STRDESC("AV_386_FPU"),
255 STRDESC("FPU"), STRDESC("fpu"),
256 },
257 { /* 0x00000002 */
258 AV_386_TSC, STRDESC("AV_386_TSC"),
259 STRDESC("TSC"), STRDESC("tsc"),
260 },
261 { /* 0x00000004 */
262 AV_386_CX8, STRDESC("AV_386_CX8"),
263 STRDESC("CX8"), STRDESC("cx8"),
264 },
265 { /* 0x00000008 */
266 AV_386_SEP, STRDESC("AV_386_SEP"),
267 STRDESC("SEP"), STRDESC("sep"),
268 },
269 { /* 0x00000010 */
270 AV_386_AMD_SYSC, STRDESC("AV_386_AMD_SYSC"),
271 STRDESC("AMD_SYSC"), STRDESC("amd_sysc"),
272 },
273 { /* 0x00000020 */
274 AV_386_CMOV, STRDESC("AV_386_CMOV"),
275 STRDESC("CMOV"), STRDESC("cmov"),
276 },
277 { /* 0x00000040 */
278 AV_386_MMX, STRDESC("AV_386_MMX"),
279 STRDESC("MMX"), STRDESC("mmx"),
280 },
281 { /* 0x00000080 */
282 AV_386_AMD_MMX, STRDESC("AV_386_AMD_MMX"),
283 STRDESC("AMD_MMX"), STRDESC("amd_mmx"),
284 },
285 { /* 0x00000100 */
286 AV_386_AMD_3DNow, STRDESC("AV_386_AMD_3DNow"),
287 STRDESC("AMD_3DNow"), STRDESC("amd_3dnow"),
288 },
289 { /* 0x00000200 */
290 AV_386_AMD_3DNowx, STRDESC("AV_386_AMD_3DNowx"),
291 STRDESC("AMD_3DNowx"), STRDESC("amd_3dnowx"),
292 },
293 { /* 0x00000400 */
294 AV_386_FXSR, STRDESC("AV_386_FXSR"),
295 STRDESC("FXSR"), STRDESC("fxsr"),
296 },
297 { /* 0x00000800 */
298 AV_386_SSE, STRDESC("AV_386_SSE"),
299 STRDESC("SSE"), STRDESC("sse"),
300 },
301 { /* 0x00001000 */
302 AV_386_SSE2, STRDESC("AV_386_SSE2"),
303 STRDESC("SSE2"), STRDESC("sse2"),
304 },
305 /* 0x02000 withdrawn - do not assign */
306 { /* 0x00004000 */
307 AV_386_SSE3, STRDESC("AV_386_SSE3"),
308 STRDESC("SSE3"), STRDESC("sse3"),
309 },
310 /* 0x08000 withdrawn - do not assign */
311 { /* 0x00010000 */
312 AV_386_CX16, STRDESC("AV_386_CX16"),
313 STRDESC("CX16"), STRDESC("cx16"),
314 },
315 { /* 0x00020000 */
316 AV_386_AHF, STRDESC("AV_386_AHF"),
317 STRDESC("AHF"), STRDESC("ahf"),
318 },
319 { /* 0x00040000 */
320 AV_386_TSCP, STRDESC("AV_386_TSCP"),
321 STRDESC("TSCP"), STRDESC("tscp"),
322 },
323 { /* 0x00080000 */
324 AV_386_AMD_SSE4A, STRDESC("AV_386_AMD_SSE4A"),
325 STRDESC("AMD_SSE4A"), STRDESC("amd_sse4a"),
326 },
327 { /* 0x00100000 */
328 AV_386_POPCNT, STRDESC("AV_386_POPCNT"),
329 STRDESC("POPCNT"), STRDESC("popcnt"),
330 },
331 { /* 0x00200000 */
332 AV_386_AMD_LZCNT, STRDESC("AV_386_AMD_LZCNT"),
333 STRDESC("AMD_LZCNT"), STRDESC("amd_lzcnt"),
334 },
335 { /* 0x00400000 */
336 AV_386_SSSE3, STRDESC("AV_386_SSSE3"),
337 STRDESC("SSSE3"), STRDESC("ssse3"),
338 },
339 { /* 0x00800000 */
340 AV_386_SSE4_1, STRDESC("AV_386_SSE4_1"),
341 STRDESC("SSE4.1"), STRDESC("sse4.1"),
342 },
343 { /* 0x01000000 */
344 AV_386_SSE4_2, STRDESC("AV_386_SSE4_2"),
345 STRDESC("SSE4.2"), STRDESC("sse4.2"),
346 },
347 { /* 0x02000000 */
348 AV_386_MOVBE, STRDESC("AV_386_MOVBE"),
349 STRDESC("MOVBE"), STRDESC("movbe"),
350 },
351 { /* 0x04000000 */
352 AV_386_AES, STRDESC("AV_386_AES"),
353 STRDESC("AES"), STRDESC("aes"),
354 },
355 { /* 0x08000000 */
356 AV_386_PCLMULQDQ, STRDESC("AV_386_PCLMULQDQ"),
357 STRDESC("PCLMULQDQ"), STRDESC("pclmulqdq"),
358 },
359 { /* 0x10000000 */
360 AV_386_XSAVE, STRDESC("AV_386_XSAVE"),
361 STRDESC("XSAVE"), STRDESC("xsave"),
362 },
363 { /* 0x20000000 */
364 AV_386_AVX, STRDESC("AV_386_AVX"),
365 STRDESC("AVX"), STRDESC("avx"),
366 },
367 { /* 0x40000000 */
368 AV_386_VMX, STRDESC("AV_386_VMX"),
369 STRDESC("VMX"), STRDESC("vmx"),
370 },
371 { /* 0x80000000 */
372 AV_386_AMD_SVM, STRDESC("AV_386_AMD_SVM"),
373 STRDESC("AMD_SVM"), STRDESC("amd_svm"),
374 }
375 };
376
377 static const elfcap_desc_t hw2_386[ELFCAP_NUM_HW2_386] = {
378 { /* 0x00000001 */
379 AV_386_2_F16C, STRDESC("AV_386_2_F16C"),
380 STRDESC("F16C"), STRDESC("f16c"),
381 },
382 { /* 0x00000002 */
383 AV_386_2_RDRAND, STRDESC("AV_386_2_RDRAND"),
384 STRDESC("RDRAND"), STRDESC("rdrand"),
385 },
386 { /* 0x00000004 */
387 AV_386_2_BMI1, STRDESC("AV_386_2_BMI1"),
388 STRDESC("BMI1"), STRDESC("bmi1"),
389 },
390 { /* 0x00000008 */
391 AV_386_2_BMI2, STRDESC("AV_386_2_BMI2"),
392 STRDESC("BMI2"), STRDESC("bmi2"),
393 },
394 { /* 0x00000010 */
395 AV_386_2_FMA, STRDESC("AV_386_2_FMA"),
396 STRDESC("FMA"), STRDESC("fma"),
397 },
398 { /* 0x00000020 */
399 AV_386_2_AVX2, STRDESC("AV_386_2_AVX2"),
400 STRDESC("AVX2"), STRDESC("avx2"),
401 },
402 { /* 0x00000040 */
403 AV_386_2_ADX, STRDESC("AV_386_2_ADX"),
404 STRDESC("ADX"), STRDESC("adx"),
405 },
406 { /* 0x00000080 */
407 AV_386_2_RDSEED, STRDESC("AV_386_2_RDSEED"),
408 STRDESC("RDSEED"), STRDESC("rdseed"),
409 },
410 { /* 0x00000100 */
411 AV_386_2_AVX512F, STRDESC("AV_386_2_AVX512F"),
412 STRDESC("AVX512F"), STRDESC("avx512f"),
413 },
414 { /* 0x00000200 */
415 AV_386_2_AVX512DQ, STRDESC("AV_386_2_AVX512DQ"),
416 STRDESC("AVX512DQ"), STRDESC("avx512dq"),
417 },
418 { /* 0x00000400 */
419 AV_386_2_AVX512IFMA, STRDESC("AV_386_2_AVX512IFMA"),
420 STRDESC("AVX512IFMA"), STRDESC("avx512ifma"),
421 },
422 { /* 0x00000800 */
423 AV_386_2_AVX512PF, STRDESC("AV_386_2_AVX512PF"),
424 STRDESC("AVX512PF"), STRDESC("avx512pf"),
425 },
426 { /* 0x00001000 */
427 AV_386_2_AVX512ER, STRDESC("AV_386_2_AVX512ER"),
428 STRDESC("AVX512ER"), STRDESC("avx512er"),
429 },
430 { /* 0x00002000 */
431 AV_386_2_AVX512CD, STRDESC("AV_386_2_AVX512CD"),
432 STRDESC("AVX512CD"), STRDESC("avx512cd"),
433 },
434 { /* 0x00004000 */
435 AV_386_2_AVX512BW, STRDESC("AV_386_2_AVX512BW"),
436 STRDESC("AVX512BW"), STRDESC("avx512bw"),
437 },
438 { /* 0x00008000 */
439 AV_386_2_AVX512VL, STRDESC("AV_386_2_AVX512VL"),
440 STRDESC("AVX512VL"), STRDESC("avx512vl"),
441 },
442 { /* 0x00010000 */
443 AV_386_2_AVX512VBMI, STRDESC("AV_386_2_AVX512VBMI"),
444 STRDESC("AVX512VBMI"), STRDESC("avx512vbmi"),
445 },
446 { /* 0x00020000 */
447 AV_386_2_AVX512VPOPCDQ, STRDESC("AV_386_2_AVX512_VPOPCDQ"),
448 STRDESC("AVX512_VPOPCDQ"), STRDESC("avx512_vpopcntdq"),
449 },
450 { /* 0x00040000 */
451 AV_386_2_AVX512_4NNIW, STRDESC("AV_386_2_AVX512_4NNIW"),
452 STRDESC("AVX512_4NNIW"), STRDESC("avx512_4nniw"),
453 },
454 { /* 0x00080000 */
455 AV_386_2_AVX512_4FMAPS, STRDESC("AV_386_2_AVX512_4FMAPS"),
456 STRDESC("AVX512_4FMAPS"), STRDESC("avx512_4fmaps"),
457 },
458 { /* 0x00100000 */
459 AV_386_2_SHA, STRDESC("AV_386_2_SHA"),
460 STRDESC("SHA"), STRDESC("sha"),
461 },
462 { /* 0x00200000 */
463 AV_386_2_FSGSBASE, STRDESC("AV_386_2_FSGSBASE"),
464 STRDESC("FSGSBASE"), STRDESC("fsgsbase")
465 },
466 { /* 0x00400000 */
467 AV_386_2_CLFLUSHOPT, STRDESC("AV_386_2_CLFLUSHOPT"),
468 STRDESC("CLFLUSHOPT"), STRDESC("clflushopt")
469 },
470 { /* 0x00800000 */
471 AV_386_2_CLWB, STRDESC("AV_386_2_CLWB"),
472 STRDESC("CLWB"), STRDESC("clwb")
473 },
474 { /* 0x01000000 */
475 AV_386_2_MONITORX, STRDESC("AV_386_2_MONITORX"),
476 STRDESC("MONITORX"), STRDESC("monitorx")
477 },
478 { /* 0x02000000 */
479 AV_386_2_CLZERO, STRDESC("AV_386_2_CLZERO"),
480 STRDESC("CLZERO"), STRDESC("clzero")
481 },
482 { /* 0x04000000 */
483 AV_386_2_AVX512_VNNI, STRDESC("AV_386_2_AVX512_VNNI"),
484 STRDESC("AVX512_VNNI"), STRDESC("avx512_vnni")
485 },
486 { /* 0x08000000 */
487 AV_386_2_VPCLMULQDQ, STRDESC("AV_386_2_VPCLMULQDQ"),
488 STRDESC("VPCLMULQDQ"), STRDESC("vpclmulqdq")
489 },
490 { /* 0x10000000 */
491 AV_386_2_VAES, STRDESC("AV_386_2_VAES"),
492 STRDESC("VAES"), STRDESC("vaes")
493 },
494 { /* 0x20000000 */
495 AV_386_2_GFNI, STRDESC("AV_386_2_GFNI"),
496 STRDESC("GFNI"), STRDESC("gfni")
497 },
498 { /* 0x40000000 */
499 AV_386_2_AVX512_VP2INT, STRDESC("AV_386_2_AVX512_VP2INT"),
500 STRDESC("AVX512_VP2INT"), STRDESC("avx512_vp2int")
501 },
502 { /* 0x80000000 */
503 AV_386_2_AVX512_BITALG, STRDESC("AV_386_2_AVX512_BITALG"),
504 STRDESC("AVX512_BITALG"), STRDESC("avx512_bitalg")
505 }
506 };
507
508 static const elfcap_desc_t hw3_386[ELFCAP_NUM_HW3_386] = {
509 { /* 0x00000001 */
510 AV_386_3_AVX512_VBMI2, STRDESC("AV_386_3_AVX512_VBMI2"),
511 STRDESC("AVX512_VBMI2"), STRDESC("avx512_vbmi2")
512 },
513 { /* 0x00000002 */
514 AV_386_3_AVX512_BF16, STRDESC("AV_386_3_AVX512_BF16"),
515 STRDESC("AVX512_BF16"), STRDESC("avx512_bf16")
516 }
517 };
518
519 /*
520 * Concatenate a token to the string buffer. This can be a capabilities token
521 * or a separator token.
522 */
523 static elfcap_err_t
token(char ** ostr,size_t * olen,const elfcap_str_t * nstr)524 token(char **ostr, size_t *olen, const elfcap_str_t *nstr)
525 {
526 if (*olen < nstr->s_len)
527 return (ELFCAP_ERR_BUFOVFL);
528
529 (void) strcat(*ostr, nstr->s_str);
530 *ostr += nstr->s_len;
531 *olen -= nstr->s_len;
532
533 return (ELFCAP_ERR_NONE);
534 }
535
536 static elfcap_err_t
get_str_desc(elfcap_style_t style,const elfcap_desc_t * cdp,const elfcap_str_t ** ret_str)537 get_str_desc(elfcap_style_t style, const elfcap_desc_t *cdp,
538 const elfcap_str_t **ret_str)
539 {
540 switch (ELFCAP_STYLE_MASK(style)) {
541 case ELFCAP_STYLE_FULL:
542 *ret_str = &cdp->c_full;
543 break;
544 case ELFCAP_STYLE_UC:
545 *ret_str = &cdp->c_uc;
546 break;
547 case ELFCAP_STYLE_LC:
548 *ret_str = &cdp->c_lc;
549 break;
550 default:
551 return (ELFCAP_ERR_INVSTYLE);
552 }
553
554 return (ELFCAP_ERR_NONE);
555 }
556
557
558 /*
559 * Expand a capabilities value into the strings defined in the associated
560 * capabilities descriptor.
561 */
562 static elfcap_err_t
expand(elfcap_style_t style,elfcap_mask_t val,const elfcap_desc_t * cdp,uint_t cnum,char * str,size_t slen,elfcap_fmt_t fmt)563 expand(elfcap_style_t style, elfcap_mask_t val, const elfcap_desc_t *cdp,
564 uint_t cnum, char *str, size_t slen, elfcap_fmt_t fmt)
565 {
566 uint_t cnt;
567 int follow = 0, err;
568 const elfcap_str_t *nstr;
569
570 if (val == 0)
571 return (ELFCAP_ERR_NONE);
572
573 for (cnt = cnum; cnt > 0; cnt--) {
574 uint_t mask = cdp[cnt - 1].c_val;
575
576 if ((val & mask) != 0) {
577 if (follow++ && ((err = token(&str, &slen,
578 &format[fmt])) != ELFCAP_ERR_NONE))
579 return (err);
580
581 err = get_str_desc(style, &cdp[cnt - 1], &nstr);
582 if (err != ELFCAP_ERR_NONE)
583 return (err);
584 if ((err = token(&str, &slen, nstr)) != ELFCAP_ERR_NONE)
585 return (err);
586
587 val = val & ~mask;
588 }
589 }
590
591 /*
592 * If there are any unknown bits remaining display the numeric value.
593 */
594 if (val) {
595 if (follow && ((err = token(&str, &slen, &format[fmt])) !=
596 ELFCAP_ERR_NONE))
597 return (err);
598
599 (void) snprintf(str, slen, "0x%x", val);
600 }
601 return (ELFCAP_ERR_NONE);
602 }
603
604 /*
605 * Expand a CA_SUNW_HW_1 value.
606 */
607 elfcap_err_t
elfcap_hw1_to_str(elfcap_style_t style,elfcap_mask_t val,char * str,size_t len,elfcap_fmt_t fmt,ushort_t mach)608 elfcap_hw1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
609 size_t len, elfcap_fmt_t fmt, ushort_t mach)
610 {
611 /*
612 * Initialize the string buffer, and validate the format request.
613 */
614 *str = '\0';
615 if ((fmt < 0) || (fmt >= FORMAT_NELTS))
616 return (ELFCAP_ERR_INVFMT);
617
618 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
619 return (expand(style, val, &hw1_386[0], ELFCAP_NUM_HW1_386,
620 str, len, fmt));
621
622 if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
623 (mach == EM_SPARCV9))
624 return (expand(style, val, hw1_sparc, ELFCAP_NUM_HW1_SPARC,
625 str, len, fmt));
626
627 return (ELFCAP_ERR_UNKMACH);
628 }
629
630 /*
631 * Expand a CA_SUNW_HW_2 value.
632 */
633 elfcap_err_t
elfcap_hw2_to_str(elfcap_style_t style,elfcap_mask_t val,char * str,size_t len,elfcap_fmt_t fmt,ushort_t mach)634 elfcap_hw2_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
635 size_t len, elfcap_fmt_t fmt, ushort_t mach)
636 {
637 /*
638 * Initialize the string buffer, and validate the format request.
639 */
640 *str = '\0';
641 if ((fmt < 0) || (fmt >= FORMAT_NELTS))
642 return (ELFCAP_ERR_INVFMT);
643
644 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
645 return (expand(style, val, &hw2_386[0], ELFCAP_NUM_HW2_386,
646 str, len, fmt));
647
648 return (expand(style, val, NULL, 0, str, len, fmt));
649 }
650
651 /*
652 * Expand a CA_SUNW_HW_3 value.
653 */
654 elfcap_err_t
elfcap_hw3_to_str(elfcap_style_t style,elfcap_mask_t val,char * str,size_t len,elfcap_fmt_t fmt,ushort_t mach)655 elfcap_hw3_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
656 size_t len, elfcap_fmt_t fmt, ushort_t mach)
657 {
658 /*
659 * Initialize the string buffer, and validate the format request.
660 */
661 *str = '\0';
662 if ((fmt < 0) || (fmt >= FORMAT_NELTS))
663 return (ELFCAP_ERR_INVFMT);
664
665 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
666 return (expand(style, val, &hw3_386[0], ELFCAP_NUM_HW3_386,
667 str, len, fmt));
668
669 return (expand(style, val, NULL, 0, str, len, fmt));
670 }
671
672 /*
673 * Expand a CA_SUNW_SF_1 value. Note, that at present these capabilities are
674 * common across all platforms. The use of "mach" is therefore redundant, but
675 * is retained for compatibility with the interface of elfcap_hw1_to_str(), and
676 * possible future expansion.
677 */
678 elfcap_err_t
679 /* ARGSUSED4 */
elfcap_sf1_to_str(elfcap_style_t style,elfcap_mask_t val,char * str,size_t len,elfcap_fmt_t fmt,ushort_t mach)680 elfcap_sf1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
681 size_t len, elfcap_fmt_t fmt, ushort_t mach)
682 {
683 /*
684 * Initialize the string buffer, and validate the format request.
685 */
686 *str = '\0';
687 if ((fmt < 0) || (fmt >= FORMAT_NELTS))
688 return (ELFCAP_ERR_INVFMT);
689
690 return (expand(style, val, &sf1[0], ELFCAP_NUM_SF1, str, len, fmt));
691 }
692
693 /*
694 * Given a capability tag type and value, map it to a string representation.
695 */
696 elfcap_err_t
elfcap_tag_to_str(elfcap_style_t style,uint64_t tag,elfcap_mask_t val,char * str,size_t len,elfcap_fmt_t fmt,ushort_t mach)697 elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, elfcap_mask_t val,
698 char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach)
699 {
700 switch (tag) {
701 case CA_SUNW_HW_1:
702 return (elfcap_hw1_to_str(style, val, str, len, fmt, mach));
703
704 case CA_SUNW_SF_1:
705 return (elfcap_sf1_to_str(style, val, str, len, fmt, mach));
706
707 case CA_SUNW_HW_2:
708 return (elfcap_hw2_to_str(style, val, str, len, fmt, mach));
709
710 case CA_SUNW_HW_3:
711 return (elfcap_hw3_to_str(style, val, str, len, fmt, mach));
712
713 }
714
715 return (ELFCAP_ERR_UNKTAG);
716 }
717
718 /*
719 * Determine a capabilities value from a capabilities string.
720 */
721 static elfcap_mask_t
value(elfcap_style_t style,const char * str,const elfcap_desc_t * cdp,uint_t cnum)722 value(elfcap_style_t style, const char *str, const elfcap_desc_t *cdp,
723 uint_t cnum)
724 {
725 const elfcap_str_t *nstr;
726 uint_t num;
727 int err;
728
729 for (num = 0; num < cnum; num++) {
730 /*
731 * Skip "reserved" bits. These are unassigned bits in the
732 * middle of the assigned range.
733 */
734 if (cdp[num].c_val == 0)
735 continue;
736
737 if ((err = get_str_desc(style, &cdp[num], &nstr)) != 0)
738 return (err);
739 if (style & ELFCAP_STYLE_F_ICMP) {
740 if (strcasecmp(str, nstr->s_str) == 0)
741 return (cdp[num].c_val);
742 } else {
743 if (strcmp(str, nstr->s_str) == 0)
744 return (cdp[num].c_val);
745 }
746 }
747
748 return (0);
749 }
750
751 elfcap_mask_t
elfcap_sf1_from_str(elfcap_style_t style,const char * str,ushort_t mach)752 elfcap_sf1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
753 {
754 return (value(style, str, &sf1[0], ELFCAP_NUM_SF1));
755 }
756
757 elfcap_mask_t
elfcap_hw1_from_str(elfcap_style_t style,const char * str,ushort_t mach)758 elfcap_hw1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
759 {
760 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
761 return (value(style, str, &hw1_386[0], ELFCAP_NUM_HW1_386));
762
763 if ((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
764 (mach == EM_SPARCV9))
765 return (value(style, str, hw1_sparc, ELFCAP_NUM_HW1_SPARC));
766
767 return (0);
768 }
769 elfcap_mask_t
elfcap_hw2_from_str(elfcap_style_t style,const char * str,ushort_t mach)770 elfcap_hw2_from_str(elfcap_style_t style, const char *str, ushort_t mach)
771 {
772 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
773 return (value(style, str, &hw2_386[0], ELFCAP_NUM_HW2_386));
774
775 return (0);
776 }
777 elfcap_mask_t
elfcap_hw3_from_str(elfcap_style_t style,const char * str,ushort_t mach)778 elfcap_hw3_from_str(elfcap_style_t style, const char *str, ushort_t mach)
779 {
780 if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
781 return (value(style, str, &hw3_386[0], ELFCAP_NUM_HW3_386));
782
783 return (0);
784 }
785
786
787 /*
788 * Given a capability tag type and value, return the capabilities values
789 * contained in the string.
790 */
791 elfcap_mask_t
elfcap_tag_from_str(elfcap_style_t style,uint64_t tag,const char * str,ushort_t mach)792 elfcap_tag_from_str(elfcap_style_t style, uint64_t tag, const char *str,
793 ushort_t mach)
794 {
795 switch (tag) {
796 case CA_SUNW_HW_1:
797 return (elfcap_hw1_from_str(style, str, mach));
798
799 case CA_SUNW_SF_1:
800 return (elfcap_sf1_from_str(style, str, mach));
801
802 case CA_SUNW_HW_2:
803 return (elfcap_hw2_from_str(style, str, mach));
804
805 case CA_SUNW_HW_3:
806 return (elfcap_hw3_from_str(style, str, mach));
807 }
808
809 return (0);
810 }
811
812 /*
813 * These functions allow the caller to get direct access to the
814 * cap descriptors.
815 */
816 const elfcap_str_t *
elfcap_getdesc_formats(void)817 elfcap_getdesc_formats(void)
818 {
819 return (format);
820 }
821
822 const elfcap_desc_t *
elfcap_getdesc_hw1_sparc(void)823 elfcap_getdesc_hw1_sparc(void)
824 {
825 return (hw1_sparc);
826 }
827
828 const elfcap_desc_t *
elfcap_getdesc_hw1_386(void)829 elfcap_getdesc_hw1_386(void)
830 {
831 return (hw1_386);
832 }
833
834 const elfcap_desc_t *
elfcap_getdesc_sf1(void)835 elfcap_getdesc_sf1(void)
836 {
837 return (sf1);
838 }
839
840 const elfcap_desc_t *
elfcap_getdesc_hw2_386(void)841 elfcap_getdesc_hw2_386(void)
842 {
843 return (hw2_386);
844 }
845
846 const elfcap_desc_t *
elfcap_getdesc_hw3_386(void)847 elfcap_getdesc_hw3_386(void)
848 {
849 return (hw3_386);
850 }
851