|
root / base / usr / src / cmd / sgs / elfcap.chk / elfcap_chk.c
elfcap_chk.c C 163 lines 4.3 KB
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2022 Oxide Computer Company
 */

/*
 * This tool is used to try and figure out what the value of various static
 * buffers should be and if the current compile time defaults are correct. In
 * particular, this covers the various elfcap values and is used to drive how we
 * calculate the overall size definition.
 *
 * To calculate this, we assume the following:
 *
 *   o We are using the ELFCAP_FMT_PIPSPACE as that is the longest. We don't
 *     have access to the actual strings right now.
 *   o We are using the ELFCAP_STYLE_FULL variant of the name as that's the
 *     longest.
 *   o We are going to have leftover bits that we don't know (unless we have
 *     32-bits defined). This uses the 0x%x format and therefore is 10
 *     characters.
 *   o We check all architectures set of values and take the largest.
 *
 * While elfcap related information is in multiple places in the build, sgs and
 * libconv are the places that seem most intertwined. In particular, we believe
 * it's important that this program execute as part of make check and also get
 * rebuilt normally as part of a build. This also allows one to iterate in
 * cmd/sgs which is the most common place that you're working in when adding new
 * hardware capabilities. By making it a part of the cmd/sgs suite, that also
 * ensures that normal build logic always rebuilds this program with changes to
 * elfcap.[ch].
 */

#include <stdio.h>
#include <elfcap.h>
#include <sys/sysmacros.h>
#include <stdlib.h>

/*
 * The length of 0x%x.
 */
#define	ECS_UNKNOWN	10

typedef const elfcap_desc_t *(*elfcap_getdesc_f)(void);

typedef struct elfcap_getdesc {
	uint32_t eg_nents;
	elfcap_getdesc_f eg_func;
} elfcap_getdesc_t;

#define	NUM_PLATS 2 /* i386, sparc */

typedef struct elfcap_case {
	const char *ec_tag;
	size_t ec_header;
	elfcap_getdesc_t ec_descs[NUM_PLATS];
} elfcap_case_t;

const elfcap_case_t elfcaps[] = {
	{ "ELFCAP_SF1_BUFSIZE", ELFCAP_SF1_BUFSIZE, {
	    { ELFCAP_NUM_SF1, elfcap_getdesc_sf1 },
	    { 0, NULL }
	} },
	{ "ELFCAP_HW1_BUFSIZE", ELFCAP_HW1_BUFSIZE, {
	    { ELFCAP_NUM_HW1_386, elfcap_getdesc_hw1_386 },
	    { ELFCAP_NUM_HW1_SPARC, elfcap_getdesc_hw1_sparc }
	} },
	{ "ELFCAP_HW2_BUFSIZE", ELFCAP_HW2_BUFSIZE, {
	    { ELFCAP_NUM_HW2_386, elfcap_getdesc_hw2_386 },
	    { 0, NULL }
	} },
	{ "ELFCAP_HW3_BUFSIZE", ELFCAP_HW3_BUFSIZE, {
	    { ELFCAP_NUM_HW3_386, elfcap_getdesc_hw3_386 },
	    { 0, NULL }
	} },
};

static size_t
elfcap_calc_len(const elfcap_desc_t *desc, uint32_t nents, size_t space)
{
	size_t len = 0;

	for (uint32_t i = 0; i < nents; i++) {
		len += desc[i].c_full.s_len;
		if (i > 0) {
			len += space;
		}
	}

	if (nents < 32) {
		len += space + ECS_UNKNOWN;
	}

	/*
	 * Finally, add one for a terminator and we add an 8 character buffer in
	 * case we screwed up.
	 */
	len += 9;

	return (len);
}

static size_t
elfcap_max_len(const elfcap_case_t *ec, size_t slen)
{
	size_t max = 0;

	for (size_t i = 0; i < ARRAY_SIZE(ec->ec_descs); i++) {
		const elfcap_desc_t *desc;
		size_t len;

		if (ec->ec_descs[i].eg_func == NULL)
			continue;

		desc = ec->ec_descs[i].eg_func();
		len = elfcap_calc_len(desc, ec->ec_descs[i].eg_nents, slen);
		if (len > max)
			max = len;
	}

	return (max);
}

int
main(void)
{
	size_t slen;
	const elfcap_str_t *strs;
	int ret = EXIT_SUCCESS;

	strs = elfcap_getdesc_formats();
	slen = strs[ELFCAP_FMT_PIPSPACE].s_len;

	for (size_t i = 0; i < ARRAY_SIZE(elfcaps); i++) {
		size_t out = elfcap_max_len(&elfcaps[i], slen);

		if (out != elfcaps[i].ec_header) {
			(void) fprintf(stderr, "elfcap size for %s is not "
			    "expected value!\n\tCurrent value is %zu, should "
			    "be %zu\n", elfcaps[i].ec_tag, elfcaps[i].ec_header,
			    out);
			ret = EXIT_FAILURE;
		}
	}

	if (ret != EXIT_SUCCESS) {
		(void) fprintf(stderr, "please update $SRC/common/elfcap/"
		    "elfcap.h and $SRC/cmd/sgs/include/conv.h with the new "
		    "values reported above\n");
	}

	return (ret);
}