xref: /illumos-gate/usr/src/cmd/sgs/elfcap.chk/elfcap_chk.c (revision 77c0a660417a046bfab6c8ef58d00c181c0264b3)
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 2022 Oxide Computer Company
14  */
15 
16 /*
17  * This tool is used to try and figure out what the value of various static
18  * buffers should be and if the current compile time defaults are correct. In
19  * particular, this covers the various elfcap values and is used to drive how we
20  * calculate the overall size definition.
21  *
22  * To calculate this, we assume the following:
23  *
24  *   o We are using the ELFCAP_FMT_PIPSPACE as that is the longest. We don't
25  *     have access to the actual strings right now.
26  *   o We are using the ELFCAP_STYLE_FULL variant of the name as that's the
27  *     longest.
28  *   o We are going to have leftover bits that we don't know (unless we have
29  *     32-bits defined). This uses the 0x%x format and therefore is 10
30  *     characters.
31  *   o We check all architectures set of values and take the largest.
32  *
33  * While elfcap related information is in multiple places in the build, sgs and
34  * libconv are the places that seem most intertwined. In particular, we believe
35  * it's important that this program execute as part of make check and also get
36  * rebuilt normally as part of a build. This also allows one to iterate in
37  * cmd/sgs which is the most common place that you're working in when adding new
38  * hardware capabilities. By making it a part of the cmd/sgs suite, that also
39  * ensures that normal build logic always rebuilds this program with changes to
40  * elfcap.[ch].
41  */
42 
43 #include <stdio.h>
44 #include <elfcap.h>
45 #include <sys/sysmacros.h>
46 #include <stdlib.h>
47 
48 /*
49  * The length of 0x%x.
50  */
51 #define	ECS_UNKNOWN	10
52 
53 typedef const elfcap_desc_t *(*elfcap_getdesc_f)(void);
54 
55 typedef struct elfcap_getdesc {
56 	uint32_t eg_nents;
57 	elfcap_getdesc_f eg_func;
58 } elfcap_getdesc_t;
59 
60 typedef struct elfcap_case {
61 	const char *ec_tag;
62 	size_t ec_header;
63 	elfcap_getdesc_t ec_descs[2];
64 } elfcap_case_t;
65 
66 const elfcap_case_t elfcaps[] = {
67 	{ "ELFCAP_SF1_BUFSIZE", ELFCAP_SF1_BUFSIZE, {
68 	    { ELFCAP_NUM_SF1, elfcap_getdesc_sf1 },
69 	    { 0, NULL }
70 	} },
71 	{ "ELFCAP_HW1_BUFSIZE", ELFCAP_HW1_BUFSIZE, {
72 	    { ELFCAP_NUM_HW1_386, elfcap_getdesc_hw1_386 },
73 	    { ELFCAP_NUM_HW1_SPARC, elfcap_getdesc_hw1_sparc }
74 	} },
75 	{ "ELFCAP_HW1_BUFSIZE", ELFCAP_HW2_BUFSIZE, {
76 	    { ELFCAP_NUM_HW2_386, elfcap_getdesc_hw2_386 },
77 	    { 0, NULL }
78 	} },
79 	{ "ELFCAP_HW1_BUFSIZE", ELFCAP_HW3_BUFSIZE, {
80 	    { ELFCAP_NUM_HW3_386, elfcap_getdesc_hw3_386 },
81 	    { 0, NULL }
82 	} },
83 };
84 
85 static size_t
86 elfcap_calc_len(const elfcap_desc_t *desc, uint32_t nents, size_t space)
87 {
88 	size_t len = 0;
89 
90 	for (uint32_t i = 0; i < nents; i++) {
91 		len += desc[i].c_full.s_len;
92 		if (i > 0) {
93 			len += space;
94 		}
95 	}
96 
97 	if (nents < 32) {
98 		len += space + ECS_UNKNOWN;
99 	}
100 
101 	/*
102 	 * Finally, add one for a terminator and we add an 8 character buffer in
103 	 * case we screwed up.
104 	 */
105 	len += 9;
106 
107 	return (len);
108 }
109 
110 static size_t
111 elfcap_max_len(const elfcap_case_t *ec, size_t slen)
112 {
113 	size_t max = 0;
114 
115 	for (size_t i = 0; i < ARRAY_SIZE(ec->ec_descs); i++) {
116 		const elfcap_desc_t *desc;
117 		size_t len;
118 
119 		if (ec->ec_descs[i].eg_func == NULL)
120 			continue;
121 
122 		desc = ec->ec_descs[i].eg_func();
123 		len = elfcap_calc_len(desc, ec->ec_descs[i].eg_nents, slen);
124 		if (len > max)
125 			max = len;
126 	}
127 
128 	return (max);
129 }
130 
131 int
132 main(void)
133 {
134 	size_t slen;
135 	const elfcap_str_t *strs;
136 	int ret = EXIT_SUCCESS;
137 
138 	strs = elfcap_getdesc_formats();
139 	slen = strs[ELFCAP_FMT_PIPSPACE].s_len;
140 
141 	for (size_t i = 0; i < ARRAY_SIZE(elfcaps); i++) {
142 		size_t out = elfcap_max_len(&elfcaps[i], slen);
143 
144 		if (out != elfcaps[i].ec_header) {
145 			(void) fprintf(stderr, "elfcap size for %s is not "
146 			    "expected value!\n\tCurrent value is %zu, should "
147 			    "be %zu\n", elfcaps[i].ec_tag, elfcaps[i].ec_header,
148 			    out);
149 			ret = EXIT_FAILURE;
150 		}
151 	}
152 
153 	if (ret != EXIT_SUCCESS) {
154 		(void) fprintf(stderr, "please update $SRC/common/elfcap/"
155 		    "elfcap.h and $SRC/cmd/sgs/include/conv.h with the new "
156 		    "values reported above\n");
157 	}
158 
159 	return (ret);
160 }
161