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