/* * 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 #include #include #include /* * 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); }