root/usr/src/test/util-tests/tests/ctf/check-merge-forward.c
/*
 * 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 (c) 2019, Joyent, Inc.
 */

/*
 * This tests that a forward declared in one object file that is defined in
 * another doesn't end up in the final one.
 */

#include "check-common.h"

static check_symbol_t check_syms[] = {
        { "list", "foo_list_t" },
        { NULL }
};

static check_member_t check_member_foo_list[] = {
        { "count", "int", 0 },
#ifdef  TARGET_LP64
        { "head", "struct foo *", 8 * NBBY },
        { "tail", "struct foo *", 16 * NBBY },
#else
        { "head", "struct foo *", 4 * NBBY },
        { "tail", "struct foo *", 8 * NBBY },
#endif
        { NULL }
};

static check_member_t check_member_foo[] = {
        { "next", "struct foo *", 0 * NBBY },
#ifdef  TARGET_LP64
        { "left", "int", 8 * NBBY },
        { "right", "int", 12 * NBBY },
        { "count", "int", 16 * NBBY },
#else
        { "left", "int", 4 * NBBY },
        { "right", "int", 8 * NBBY },
        { "count", "int", 12 * NBBY },
#endif
        { NULL }
};

static check_member_test_t members[] = {
#ifdef  TARGET_LP64
        { "struct foo_list", CTF_K_STRUCT, 24, check_member_foo_list },
        { "struct foo", CTF_K_STRUCT, 24, check_member_foo },
#else
        { "struct foo_list", CTF_K_STRUCT, 12, check_member_foo_list },
        { "struct foo", CTF_K_STRUCT, 16, check_member_foo },
#endif
        { NULL }
};

static int
ctf_merge_forward_cb(ctf_id_t id, boolean_t root, void *arg)
{
        ctf_file_t *fp = arg;
        char buf[2048];

        if (ctf_type_kind(fp, id) != CTF_K_FORWARD)
                return (0);

        if (ctf_type_name(fp, id, buf, sizeof (buf)) == NULL) {
                warnx("failed to lookup the name of type %ld: %s", id,
                    ctf_errmsg(ctf_errno(fp)));
                return (1);
        }

        /*
         * If a forward shows up, that's OK. It's only bad if it's the name of
         * the one we created.
         */
        if (strcmp("struct foo", buf) == 0) {
                warnx("encountered forward type for struct foo that "
                    "shouldn't exist");
                return (1);
        }

        return (0);
}

int
main(int argc, char *argv[])
{
        int i, ret = 0;

        if (argc < 2) {
                errx(EXIT_FAILURE, "missing test files");
        }

        for (i = 1; i < argc; i++) {
                ctf_file_t *fp;
                uint_t j;

                if ((fp = ctf_open(argv[i], &ret)) == NULL) {
                        warnx("failed to open %s: %s", argv[i],
                            ctf_errmsg(ret));
                        ret = EXIT_FAILURE;
                        continue;
                }

                if (!ctftest_check_symbols(fp, check_syms))
                        ret = EXIT_FAILURE;

                for (j = 0; members[j].cmt_type != NULL; j++) {
                        if (!ctftest_check_members(members[j].cmt_type, fp,
                            members[j].cmt_kind, members[j].cmt_size,
                            members[j].cmt_members)) {
                                ret = EXIT_FAILURE;
                        }
                }

                if (ctf_type_iter(fp, B_TRUE, ctf_merge_forward_cb, fp) != 0) {
                        ret = EXIT_FAILURE;
                }

                ctf_close(fp);
        }

        return (ret);
}