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 #define	NUM_PLATS 2 /* i386, sparc */
61 
62 typedef struct elfcap_case {
63 	const char *ec_tag;
64 	size_t ec_header;
65 	elfcap_getdesc_t ec_descs[NUM_PLATS];
66 } elfcap_case_t;
67 
68 const elfcap_case_t elfcaps[] = {
69 	{ "ELFCAP_SF1_BUFSIZE", ELFCAP_SF1_BUFSIZE, {
70 	    { ELFCAP_NUM_SF1, elfcap_getdesc_sf1 },
71 	    { 0, NULL }
72 	} },
73 	{ "ELFCAP_HW1_BUFSIZE", ELFCAP_HW1_BUFSIZE, {
74 	    { ELFCAP_NUM_HW1_386, elfcap_getdesc_hw1_386 },
75 	    { ELFCAP_NUM_HW1_SPARC, elfcap_getdesc_hw1_sparc }
76 	} },
77 	{ "ELFCAP_HW2_BUFSIZE", ELFCAP_HW2_BUFSIZE, {
78 	    { ELFCAP_NUM_HW2_386, elfcap_getdesc_hw2_386 },
79 	    { 0, NULL }
80 	} },
81 	{ "ELFCAP_HW3_BUFSIZE", ELFCAP_HW3_BUFSIZE, {
82 	    { ELFCAP_NUM_HW3_386, elfcap_getdesc_hw3_386 },
83 	    { 0, NULL }
84 	} },
85 };
86 
87 static size_t
elfcap_calc_len(const elfcap_desc_t * desc,uint32_t nents,size_t space)88 elfcap_calc_len(const elfcap_desc_t *desc, uint32_t nents, size_t space)
89 {
90 	size_t len = 0;
91 
92 	for (uint32_t i = 0; i < nents; i++) {
93 		len += desc[i].c_full.s_len;
94 		if (i > 0) {
95 			len += space;
96 		}
97 	}
98 
99 	if (nents < 32) {
100 		len += space + ECS_UNKNOWN;
101 	}
102 
103 	/*
104 	 * Finally, add one for a terminator and we add an 8 character buffer in
105 	 * case we screwed up.
106 	 */
107 	len += 9;
108 
109 	return (len);
110 }
111 
112 static size_t
elfcap_max_len(const elfcap_case_t * ec,size_t slen)113 elfcap_max_len(const elfcap_case_t *ec, size_t slen)
114 {
115 	size_t max = 0;
116 
117 	for (size_t i = 0; i < ARRAY_SIZE(ec->ec_descs); i++) {
118 		const elfcap_desc_t *desc;
119 		size_t len;
120 
121 		if (ec->ec_descs[i].eg_func == NULL)
122 			continue;
123 
124 		desc = ec->ec_descs[i].eg_func();
125 		len = elfcap_calc_len(desc, ec->ec_descs[i].eg_nents, slen);
126 		if (len > max)
127 			max = len;
128 	}
129 
130 	return (max);
131 }
132 
133 int
main(void)134 main(void)
135 {
136 	size_t slen;
137 	const elfcap_str_t *strs;
138 	int ret = EXIT_SUCCESS;
139 
140 	strs = elfcap_getdesc_formats();
141 	slen = strs[ELFCAP_FMT_PIPSPACE].s_len;
142 
143 	for (size_t i = 0; i < ARRAY_SIZE(elfcaps); i++) {
144 		size_t out = elfcap_max_len(&elfcaps[i], slen);
145 
146 		if (out != elfcaps[i].ec_header) {
147 			(void) fprintf(stderr, "elfcap size for %s is not "
148 			    "expected value!\n\tCurrent value is %zu, should "
149 			    "be %zu\n", elfcaps[i].ec_tag, elfcaps[i].ec_header,
150 			    out);
151 			ret = EXIT_FAILURE;
152 		}
153 	}
154 
155 	if (ret != EXIT_SUCCESS) {
156 		(void) fprintf(stderr, "please update $SRC/common/elfcap/"
157 		    "elfcap.h and $SRC/cmd/sgs/include/conv.h with the new "
158 		    "values reported above\n");
159 	}
160 
161 	return (ret);
162 }
163