diff options
author | Robert Mustacchi <rm@joyent.com> | 2018-09-09 19:56:37 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2019-03-21 17:15:41 +0000 |
commit | d8fc647be2c6caf34bbf0e0b6990d1d798f0c108 (patch) | |
tree | 3ab49b134f07eaf55721406851ffedc2a3107d26 | |
parent | 554f80e97289e58da5f8cd5d6334edd78d1f0461 (diff) | |
download | illumos-joyent-d8fc647be2c6caf34bbf0e0b6990d1d798f0c108.tar.gz |
OS-7386 Want primordial CTF test suite
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: John Levon <john.levon@joyent.com>
Approved by: John Levon <john.levon@joyent.com>
50 files changed, 4694 insertions, 2 deletions
diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index 936f7c920a..cb2d3028da 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -14,11 +14,11 @@ # Copyright 2014 Garrett D'Amore <garrett@damore.org> # Copyright 2014 Nexenta Systems, Inc. All rights reserved. # Copyright 2017 Jason King -# Copyright 2018 Joyent, Inc. +# Copyright 2019 Joyent, Inc. # SUBDIRS = date dis dladm iconv libnvpair_json libsff printf xargs grep_xpg4 SUBDIRS += demangle mergeq workq chown -SUBDIRS += bunyan awk smbios libjedec +SUBDIRS += bunyan awk smbios libjedec ctf include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/ctf/Makefile b/usr/src/test/util-tests/tests/ctf/Makefile new file mode 100644 index 0000000000..007d6c1c2f --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/Makefile @@ -0,0 +1,149 @@ +# +# 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. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/util-tests +TESTDIR = $(ROOTOPTPKG)/tests/ctf + +SCRIPTS = ctftest.ksh + +TESTS = test-float.c \ + test-reference.c \ + test-int.c \ + test-array.c \ + test-enum.c \ + test-forward.c \ + test-sou.c \ + test-function.c \ + test-merge-static/Makefile.ctftest \ + test-merge-static/test-a.c \ + test-merge-static/test-b.c \ + test-merge-static/test-c.c \ + test-merge-static/test-d.c \ + test-merge-static/test-main.c \ + test-merge-forward/Makefile.ctftest \ + test-merge-forward/test-impl.c \ + test-merge-forward/test-merge.c \ + test-merge-dedup/Makefile.ctftest \ + test-merge-dedup/test-merge-1.c \ + test-merge-dedup/test-merge-2.c \ + test-merge-dedup/test-merge-3.c \ + test-merge-dedup/test-merge-dedup.c \ + test-merge-reduction/Makefile.ctftest \ + test-merge-reduction/mapfile-vers \ + test-merge-reduction/test-global.c \ + test-merge-reduction/test-scoped.c \ + test-merge-weak/Makefile.ctftest \ + test-merge-weak/test-merge-weak.c \ + test-weak.c \ + Makefile.ctftest.com + +MAKEDIRS = test-merge-static \ + test-merge-forward \ + test-merge-dedup \ + test-merge-reduction \ + test-merge-weak + +CHECKS = check-float-32 \ + check-float-64 \ + check-int-32 \ + check-int-64 \ + check-reference \ + check-array \ + check-enum \ + check-sou-32 \ + check-sou-64 \ + check-forward-32 \ + check-forward-64 \ + check-function \ + check-merge-static \ + check-merge-forward-32 \ + check-merge-forward-64 \ + check-merge-dedup \ + check-merge-reduction \ + check-merge-weak \ + check-weak + +COMMON_OBJS = check-common.o +ALL_OBJS = $(CHECKS:%=%.o) $(CHECKS:%-32=%.32.o) $(CHECKS:%-64=%.64.o) $(COMMON_OBJS) + +ROOTTESTS = $(TESTS:%=$(TESTDIR)/%) +ROOTMAKEDIRS = $(MAKEDIRS:%=$(TESTDIR)/%) +ROOTCHECKS = $(CHECKS:%=$(TESTDIR)/%) +ROOTSCRIPTS = $(SCRIPTS:%.ksh=$(TESTDIR)/%) + +ROOTTESTS := FILEMODE = 0444 +ROOTCHECKS := FILEMODE = 0555 +ROOTSCRIPTS := FILEMODE = 0555 + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +LDLIBS += -lctf + +check-merge-static := LDLIBS += -lelf + +all: $(CHECKS) + +install: all $(ROOTTESTS) $(ROOTCHECKS) $(ROOTSCRIPTS) + +$(CHECKS): $(COMMON_OBJS) + +clean: + $(RM) $(ALL_OBJS) + +clobber: clean + $(RM) $(CHECKS) + +$(ROOTTESTS): $(TESTDIR) $(ROOTMAKEDIRS) $(TESTS) +$(ROOTCHECKS): $(TESTDIR) $(CHECKS) +$(ROOTSCRIPTS): $(TESTDIR) $(SCRIPTS) + +$(TESTDIR): + $(INS.dir) + +$(ROOTMAKEDIRS): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) + +$(TESTDIR)/%: %.ksh + $(INS.rename) + +%.o: %.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.32.o: %.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%.64.o: %.c + $(COMPILE.c) -DTARGET_LP64 -o $@ $< + $(POST_PROCESS_O) + +%-32: %.32.o + $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS) + $(POST_PROCESS) + +%-64: %.64.o + $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS) + $(POST_PROCESS) + +%: %.o + $(LINK.c) -o $@ $< $(COMMON_OBJS) $(LDLIBS) + $(POST_PROCESS) diff --git a/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com new file mode 100644 index 0000000000..f3f754dbf9 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/Makefile.ctftest.com @@ -0,0 +1,92 @@ +# +# 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 2019 Joyent, Inc. +# + +# +# This Makefile is installed onto the target system and is used as part +# of the running tests. It is not used as part of the build. +# +# This makefile could be simplified substantially. However, it does +# everything explicitly to try and work with a wide variety of different +# makes. +# +# The following values should be passed in by the invoker of the +# Makefile: +# +# CC C Compiler to use +# CFLAGS32 32-bit CFLAGS +# CFLAGS64 64-bit CFLAGS +# CTFCONVERT Path to ctfconvert +# CTFMERGE Path to ctfmerge +# DEBUGFLAGS The set of debug flags to use +# BUILDDIR Directory things should be built in +# CHECK32 Program to check 32-bit output +# CHECK64 Program to check 64-bit output +# +# The following values should be set before building this: +# +# TEST The name of the test program +# OBJS_C_32 32-bit convert objects +# OBJS_C_64 64-bit convert objects +# OBJS_M_32 32-bit merge objects +# OBJS_M_64 64-bit merge objects +# + +CONV32 = $(BUILDDIR)/$(TEST)-32c +CONV64 = $(BUILDDIR)/$(TEST)-64c +MERGE32 = $(BUILDDIR)/$(TEST)-32m +MERGE64 = $(BUILDDIR)/$(TEST)-64m + +BINS = $(CONV32) \ + $(CONV64) \ + $(MERGE32) \ + $(MERGE64) + +build: $(BINS) + +$(BUILDDIR)/%.32.c.o: %.c + $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $< + +$(BUILDDIR)/%.64.c.o: %.c + $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $< + +$(BUILDDIR)/%.32.m.o: %.c + $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $< + $(CTFCONVERT) $@ + +$(BUILDDIR)/%.64.m.o: %.c + $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $< + $(CTFCONVERT) $@ + +$(CONV32): $(OBJS_C_32) + $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_C_32) + $(CTFCONVERT) $@ + +$(CONV64): $(OBJS_C_64) + $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_C_64) + $(CTFCONVERT) $@ + +$(MERGE32): $(OBJS_M_32) + $(CC) $(CFLAGS32) $(DEBUGFLAGS) -o $@ $(OBJS_M_32) + $(CTFMERGE) -t -o $@ $(OBJS_M_32) + +$(MERGE64): $(OBJS_M_64) + $(CC) $(CFLAGS64) $(DEBUGFLAGS) -o $@ $(OBJS_M_64) + $(CTFMERGE) -t -o $@ $(OBJS_M_64) + +run-test: + $(CHECK32) $(CONV32) + $(CHECK64) $(CONV64) + $(CHECK32) $(MERGE32) + $(CHECK64) $(MERGE64) diff --git a/usr/src/test/util-tests/tests/ctf/README b/usr/src/test/util-tests/tests/ctf/README new file mode 100644 index 0000000000..0f9aeb9e3a --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/README @@ -0,0 +1,54 @@ +# +# 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. +# + +CTF Tests +--------- + +This directory contains a series of tests for the Compact C Type Format +(CTF). For each test program, there is a corresponding C program that +goes through and checks the CTF for various aspects. Due to the fact +that the CTF generated by compilers can change slightly, the tests have +been designed this way to try and make it work with as wide a variety of +programs as possible. + +The test suite requires the following: + +1. make +2. C Compiler (defaults to gcc) +3. A copy of ctfconvert + +The source for a given program will be compiled on the target system and +then converted. This allows us to try the CTF tools against a wide +variety of different compilers or DWARF standards. + +Caveats +------- + +Right now the tests only pass when using gcc 4.x. The following are +known issues with the tests: + +1. gcc7+ generates some different DWARF ordering, which causes some +tests to spuriously fail. These tests should be improved. + +2. There are cases where gcc7+ appears to attribute things as being const +twice in DWARF which throw off the tests. The CTF tools likely should +work around this if we confirm that this is intentional. + +3. Many tests will cause clang not to emit DWARF information because +clang infers that they cannot be used. The tests should be cleaned up in +these cases. + +4. clang generated DWARF can confuse the CTF tools. The tools should be +fixed and additional regression tests should be added. diff --git a/usr/src/test/util-tests/tests/ctf/check-array.c b/usr/src/test/util-tests/tests/ctf/check-array.c new file mode 100644 index 0000000000..c694726a3f --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-array.c @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * Check that we properly generate basic nested arrays. + */ + +#include "check-common.h" + +static check_number_t check_base[] = { + { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, + { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 }, + { "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "a", "int [3]" }, + { "b", "double [42]" }, + { "c", "const char *[2]" }, + { "d", "int [4][5]" }, + { "e", "int [4][5][6]" }, + { "f", "int [4][5][6][7]" }, + { "g", "int [4][5][6][7][8]" }, + { "h", "int [4][5][6][7][8][9]" }, + { "i", "int [4][5][6][7][8][9][10]" }, + { NULL } +}; + +static check_descent_t check_array_a[] = { + { "int [3]", CTF_K_ARRAY, "int", 3 }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_array_b[] = { + { "double [42]", CTF_K_ARRAY, "double", 42 }, + { "double", CTF_K_FLOAT }, + { NULL } +}; + +static check_descent_t check_array_c[] = { + { "const char *[2]", CTF_K_ARRAY, "const char *", 2 }, + { "const char *", CTF_K_POINTER }, + { "const char", CTF_K_CONST }, + { "char", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_array_i[] = { + { "int [4][5][6][7][8][9][10]", CTF_K_ARRAY, + "int [5][6][7][8][9][10]", 4 }, + { "int [5][6][7][8][9][10]", CTF_K_ARRAY, "int [6][7][8][9][10]", 5 }, + { "int [6][7][8][9][10]", CTF_K_ARRAY, "int [7][8][9][10]", 6 }, + { "int [7][8][9][10]", CTF_K_ARRAY, "int [8][9][10]", 7 }, + { "int [8][9][10]", CTF_K_ARRAY, "int [9][10]", 8 }, + { "int [9][10]", CTF_K_ARRAY, "int [10]", 9 }, + { "int [10]", CTF_K_ARRAY, "int", 10 }, + { "int", CTF_K_INTEGER }, + { NULL }, +}; + +static check_descent_test_t descents[] = { + { "a", check_array_a }, + { "b", check_array_b }, + { "c", check_array_c }, + { "i", check_array_i }, + { NULL } +}; + +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 d; + + 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_numbers(fp, check_base)) + ret = EXIT_FAILURE; + if (!ctftest_check_symbols(fp, check_syms)) + ret = EXIT_FAILURE; + for (d = 0; descents[d].cdt_sym != NULL; d++) { + if (!ctftest_check_descent(descents[d].cdt_sym, fp, + descents[d].cdt_tests)) { + ret = EXIT_FAILURE; + } + } + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-common.c b/usr/src/test/util-tests/tests/ctf/check-common.c new file mode 100644 index 0000000000..8aa5449cac --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-common.c @@ -0,0 +1,802 @@ +/* + * 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. + */ + +/* + * Collection of common utilities for CTF testing. + */ + +#include <strings.h> +#include <libctf.h> +#include "check-common.h" + +typedef struct ctftests_lookup_cb { + ctf_file_t *clc_fp; + ctf_id_t clc_id; + const char *clc_name; +} ctftests_lookup_cb_t; + +typedef struct ctftest_member_cb { + ctf_file_t *cmc_fp; + const check_member_t *cmc_members; + const char *cmc_name; +} ctftest_member_cb_t; + +static int +ctftest_lookup_type_cb(ctf_id_t id, boolean_t root, void *arg) +{ + char buf[2048]; + ctftests_lookup_cb_t *clc = arg; + + if (ctf_type_name(clc->clc_fp, id, buf, sizeof (buf)) == NULL) + return (0); + + if (strcmp(buf, clc->clc_name) != 0) + return (0); + + clc->clc_id = id; + return (1); +} + +/* + * This is a variant on the classic ctf_lookup_by_name(). ctf_lookup_by_name() + * skips qualifiers, which makes sense given what the consumers of it are trying + * to do. However, that's not what we want here. So instead we basically have to + * walk the type table. + */ +static ctf_id_t +ctftest_lookup_type(ctf_file_t *fp, const char *name) +{ + ctftests_lookup_cb_t clc; + + clc.clc_fp = fp; + clc.clc_id = CTF_ERR; + clc.clc_name = name; + + (void) ctf_type_iter(fp, B_TRUE, ctftest_lookup_type_cb, &clc); + return (clc.clc_id); +} + +static int +ctftest_lookup_object_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg) +{ + ctftests_lookup_cb_t *clc = arg; + + if (strcmp(obj, clc->clc_name) == 0) { + clc->clc_id = type; + return (1); + } + + return (0); +} + +static ctf_id_t +ctftest_lookup_symbol(ctf_file_t *fp, const char *name) +{ + ctftests_lookup_cb_t clc; + + clc.clc_fp = fp; + clc.clc_id = CTF_ERR; + clc.clc_name = name; + + (void) ctf_object_iter(fp, ctftest_lookup_object_cb, &clc); + return (clc.clc_id); +} + +typedef struct ctf_function_cb { + const char *cfc_name; + ulong_t *cfc_symp; + ctf_funcinfo_t *cfc_fip; +} ctf_function_cb_t; + +static int +ctftest_lookup_function_cb(const char *name, ulong_t symidx, + ctf_funcinfo_t *fip, void *arg) +{ + ctf_function_cb_t *cfc = arg; + if (strcmp(name, cfc->cfc_name) != 0) + return (0); + + *cfc->cfc_symp = symidx; + *cfc->cfc_fip = *fip; + + return (1); +} + +/* + * Note, this function finds the first one with a matching name. This must not + * be used when performing searches where a given name may occur more than once. + */ +static boolean_t +ctftest_lookup_function(ctf_file_t *fp, const char *name, ulong_t *symp, + ctf_funcinfo_t *fip) +{ + ctf_function_cb_t cfc; + + *symp = 0; + cfc.cfc_name = name; + cfc.cfc_symp = symp; + cfc.cfc_fip = fip; + (void) ctf_function_iter(fp, ctftest_lookup_function_cb, &cfc); + return (*symp == 0 ? B_FALSE : B_TRUE); +} + +boolean_t +ctftest_check_numbers(ctf_file_t *fp, const check_number_t *tests) +{ + uint_t i; + boolean_t ret = B_TRUE; + + for (i = 0; tests[i].cn_tname != NULL; i++) { + ctf_id_t id; + ctf_encoding_t enc; + + id = ctftest_lookup_type(fp, tests[i].cn_tname); + if (id == CTF_ERR) { + warnx("failed to look up %s", tests[i].cn_tname); + ret = B_FALSE; + continue; + } + + if (ctf_type_kind(fp, id) != tests[i].cn_kind) { + warnx("type kind mismatch for %s: got %u, expected %u", + tests[i].cn_tname, ctf_type_kind(fp, id), + tests[i].cn_kind); + ret = B_FALSE; + continue; + } + + if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) { + warnx("failed to get type encoding for %s: %s", + tests[i].cn_tname, ctf_errmsg(ctf_errno(fp))); + ret = B_FALSE; + continue; + } + + if (enc.cte_format != tests[i].cn_flags) { + warnx("encoding flags mismatch for %s: got 0x%x, " + "expected 0x%x", tests[i].cn_tname, enc.cte_format, + tests[i].cn_flags); + ret = B_FALSE; + continue; + } + + if (enc.cte_offset != tests[i].cn_offset) { + warnx("encoding offset mismatch for %s: got 0x%x, " + "expected 0x%x", tests[i].cn_tname, enc.cte_offset, + tests[i].cn_offset); + ret = B_FALSE; + continue; + } + + if (enc.cte_bits != tests[i].cn_size) { + warnx("encoding size mismatch for %s: got 0x%x, " + "expected 0x%x", tests[i].cn_tname, enc.cte_bits, + tests[i].cn_size); + ret = B_FALSE; + continue; + } + } + + return (ret); +} + +typedef struct ctftests_symbol_cb { + ctf_file_t *csc_fp; + boolean_t csc_ret; + const check_symbol_t *csc_tests; +} ctftest_symbol_cb_t; + +static int +ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg) +{ + ctftest_symbol_cb_t *cb = arg; + const check_symbol_t *tests = cb->csc_tests; + ctf_file_t *fp = cb->csc_fp; + uint_t i; + + for (i = 0; tests[i].cs_symbol != NULL; i++) { + ctf_id_t id; + + if (strcmp(obj, tests[i].cs_symbol) != 0) + continue; + + id = ctftest_lookup_type(fp, tests[i].cs_type); + if (id == CTF_ERR) { + warnx("failed to lookup type %s for symbol %s", + tests[i].cs_type, tests[i].cs_symbol); + cb->csc_ret = B_FALSE; + return (0); + } + + if (id != type) { + warnx("type mismatch for symbol %s, has type id %u, " + "but specified type %s has id %u", + tests[i].cs_symbol, type, tests[i].cs_type, id); + cb->csc_ret = B_FALSE; + return (0); + } + } + + return (0); +} + +boolean_t +ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests) +{ + ctftest_symbol_cb_t cb; + + cb.csc_fp = fp; + cb.csc_ret = B_TRUE; + cb.csc_tests = tests; + if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0) + return (B_FALSE); + return (cb.csc_ret); +} + + +boolean_t +ctftest_check_descent(const char *symbol, ctf_file_t *fp, + const check_descent_t *tests) +{ + ctf_id_t base; + uint_t layer = 0; + + /* + * First, find the initial type of the symbol. + */ + base = ctftest_lookup_symbol(fp, symbol); + if (base == CTF_ERR) { + warnx("failed to lookup type for symbol %s", symbol); + return (B_FALSE); + } + + while (tests->cd_tname != NULL) { + ctf_id_t tid; + int kind; + ctf_arinfo_t ari; + + if (base == CTF_ERR) { + warnx("encountered non-reference type at layer %u " + "while still expecting type %s for symbol %s", + layer, tests->cd_tname, symbol); + return (B_FALSE); + } + + tid = ctftest_lookup_type(fp, tests->cd_tname); + if (tid == CTF_ERR) { + warnx("failed to lookup type %s", tests->cd_tname); + return (B_FALSE); + } + + if (tid != base) { + warnx("type mismatch at layer %u: found id %u, but " + "expecting type id %u for type %s, symbol %s", + layer, base, tid, tests->cd_tname, symbol); + return (B_FALSE); + } + + kind = ctf_type_kind(fp, base); + if (kind != tests->cd_kind) { + warnx("type kind mismatch at layer %u: found kind %u, " + "but expected kind %u for %s, symbol %s", layer, + kind, tests->cd_kind, tests->cd_tname, symbol); + return (B_FALSE); + } + + switch (kind) { + case CTF_K_ARRAY: + if (ctf_array_info(fp, base, &ari) == CTF_ERR) { + warnx("failed to lookup array info at layer " + "%u for type %s, symbol %s: %s", base, + tests->cd_tname, symbol, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (tests->cd_nents != ari.ctr_nelems) { + warnx("array element mismatch at layer %u " + "for type %s, symbol %s: found %u, " + "expected %u", layer, tests->cd_tname, + symbol, ari.ctr_nelems, tests->cd_nents); + return (B_FALSE); + } + + tid = ctftest_lookup_type(fp, tests->cd_contents); + if (tid == CTF_ERR) { + warnx("failed to look up type %s", + tests->cd_contents); + return (B_FALSE); + } + + if (ari.ctr_contents != tid) { + warnx("array contents mismatch at layer %u " + "for type %s, symbol %s: found %u, " + "expected %s/%u", layer, tests->cd_tname, + symbol, ari.ctr_contents, + tests->cd_contents, tid); + + return (B_FALSE); + } + base = ari.ctr_contents; + break; + default: + base = ctf_type_reference(fp, base); + break; + } + + tests++; + layer++; + } + + if (base != CTF_ERR) { + warnx("found additional type %u in chain, but expected no more", + base); + return (B_FALSE); + } + + return (B_TRUE); +} + +int +ctftest_check_enum_count(const char *name, int value, void *arg) +{ + uint_t *u = arg; + *u = *u + 1; + return (0); +} + +int +ctftest_check_enum_value(const char *name, int value, void *arg) +{ + uint_t i; + const check_enum_t *enums = arg; + + for (i = 0; enums[i].ce_name != NULL; i++) { + if (strcmp(enums[i].ce_name, name) != 0) + continue; + if (enums[i].ce_value == (int64_t)value) + return (0); + warnx("enum %s value mismatch: found %d, expected %" PRId64, + name, value, enums[i].ce_value); + return (1); + } + + warnx("found no matching entry for enum member %s", name); + return (1); +} + +boolean_t +ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums) +{ + int ret; + uint_t tcount, ecount; + ctf_id_t base; + + if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { + warnx("Failed to look up type %s", type); + return (B_FALSE); + } + + if (ctf_type_kind(fp, base) != CTF_K_ENUM) { + warnx("%s is not an enum", type); + return (B_FALSE); + } + + /* + * First count how many entries we have. + */ + tcount = 0; + while (enums[tcount].ce_name != NULL) { + tcount++; + } + + ecount = 0; + if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) { + warnx("failed to walk enum %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (tcount != ecount) { + warnx("enum value mismatch: expected %u values, but found %u", + tcount, ecount); + return (B_FALSE); + } + + if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value, + (void *)enums)) != 0) { + if (ret == -1) { + warnx("failed to walk enum %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + } + return (B_FALSE); + } + + return (B_TRUE); +} + +int +ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff, + void *arg) +{ + uint_t *countp = arg; + *countp = *countp + 1; + return (0); +} + +int +ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff, + void *arg) +{ + uint_t i; + const ctftest_member_cb_t *cmc = arg; + const check_member_t *members = cmc->cmc_members; + ctf_file_t *fp = cmc->cmc_fp; + + for (i = 0; members[i].cm_name != NULL; i++) { + boolean_t bad = B_FALSE; + char buf[2048]; + + if (strcmp(mname, members[i].cm_name) != 0) + continue; + + if (bitoff != members[i].cm_offset) { + warnx("member %s of type %s has mismatched bit offset: " + "found %lu, expected %lu", mname, cmc->cmc_name, + bitoff, members[i].cm_offset); + bad = B_TRUE; + } + + if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) { + warnx("failed to obtain type name for member %s", + mname, ctf_errmsg(ctf_errno(fp))); + bad = B_TRUE; + } else if (strcmp(buf, members[i].cm_type) != 0) { + warnx("member %s has bad type, found %s, expected %s", + mname, buf, members[i].cm_type); + bad = B_TRUE; + } + + return (bad ? 1 : 0); + } + + warnx("found no matching entry for member %s of type %s", mname, + cmc->cmc_name); + return (1); +} + +boolean_t +ctftest_check_members(const char *type, ctf_file_t *fp, int kind, + size_t size, const check_member_t *members) +{ + int ret; + uint_t tcount, mcount; + ctf_id_t base; + ctftest_member_cb_t cmc; + + if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { + warnx("failed to look up type %s", type); + return (B_FALSE); + } + + if (ctf_type_kind(fp, base) != kind) { + warnx("%s has kind %s, expected %s", type, + ctf_kind_name(fp, ctf_type_kind(fp, base)), + ctf_kind_name(fp, kind)); + return (B_FALSE); + } + + if (size != ctf_type_size(fp, base)) { + warnx("%s has bad size, expected %lu, found %lu", + type, size, ctf_type_size(fp, base)); + return (B_FALSE); + } + + /* + * First count how many entries we have. + */ + tcount = 0; + while (members[tcount].cm_name != NULL) { + tcount++; + } + + mcount = 0; + if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) != + 0) { + warnx("failed to walk members of %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (tcount != mcount) { + warnx("type member mismatch: expected %u values, but found %u", + tcount, mcount); + return (B_FALSE); + } + + cmc.cmc_fp = fp; + cmc.cmc_members = members; + cmc.cmc_name = type; + if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb, + &cmc)) != 0) { + if (ret == -1) { + warnx("failed to walk type %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + } + return (B_FALSE); + } + + return (B_TRUE); +} + +boolean_t +ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype, + uint_t nargs, uint_t flags, const char **argv) +{ + ulong_t sym; + ctf_funcinfo_t fi; + uint_t i; + boolean_t ret = B_TRUE; + ctf_id_t *args; + char buf[2048]; + + + if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) { + warnx("failed to look up function %s", symbol); + return (B_FALSE); + } + + if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { + warnx("failed to lookup return type name for function %s", + symbol); + ret = B_FALSE; + } else if (strcmp(rtype, buf) != 0) { + warnx("return type has wrong type: found %s, expected %s", + buf, rtype); + ret = B_FALSE; + } + + if (nargs != fi.ctc_argc) { + warnx("function argument mismatch: found %u, expected %u", + fi.ctc_argc, nargs); + ret = B_FALSE; + } + + if (flags != fi.ctc_flags) { + warnx("function flags mismatch, found 0x%x, expected 0x%x", + fi.ctc_flags, flags); + ret = B_FALSE; + } + + if (!ret || fi.ctc_argc == 0) { + return (ret); + } + + if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { + warnx("failed to allocate memory for function arguments"); + return (B_FALSE); + } + + if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) { + warnx("failed to get function information: %s", + ctf_errmsg(ctf_errno(fp))); + free(args); + return (B_FALSE); + } + + for (i = 0; i < fi.ctc_argc; i++) { + if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { + warnx("failed to obtain type name for argument %u", + i, ctf_errmsg(ctf_errno(fp))); + ret = B_FALSE; + break; + } + + if (strcmp(buf, argv[i]) != 0) { + warnx("argument %u has wrong type: found %s, " + "expected %s", i, buf, argv[i]); + ret = B_FALSE; + break; + } + } + + free(args); + return (ret); +} + +boolean_t +ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype, + uint_t nargs, uint_t flags, const char **argv) +{ + ctf_id_t tid; + ctf_funcinfo_t fi; + uint_t i; + boolean_t ret = B_TRUE; + ctf_id_t *args; + char buf[2048]; + + + if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) { + warnx("failed to look up type %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + /* + * Perform two CTF type resolves, one for the function pointer and one + * for the typedef that gets passed in. + */ + if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) { + warnx("failed to convert type %s to base type: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (ctf_type_kind(fp, tid) == CTF_K_POINTER && + (tid = ctf_type_reference(fp, tid)) == CTF_ERR) { + warnx("failed to convert type %s to base type: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (ctf_func_info_by_id(fp, tid, &fi) != 0) { + warnx("failed to get function information for type %s: %s", + type, ctf_errmsg(ctf_errno(fp))); + return (B_FALSE); + } + + if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { + warnx("failed to lookup return type name for function %s", + type); + ret = B_FALSE; + } else if (strcmp(rtype, buf) != 0) { + warnx("return type has wrong type: found %s, expected %s", + buf, rtype); + ret = B_FALSE; + } + + if (nargs != fi.ctc_argc) { + warnx("function argument mismatch: found %u, expected %u", + fi.ctc_argc, nargs); + ret = B_FALSE; + } + + if (flags != fi.ctc_flags) { + warnx("function flags mismatch, found 0x%x, expected 0x%x", + fi.ctc_flags, flags); + ret = B_FALSE; + } + + if (!ret || fi.ctc_argc == 0) { + return (ret); + } + + if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { + warnx("failed to allocate memory for function arguments"); + return (B_FALSE); + } + + if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) { + warnx("failed to get function information: %s", + ctf_errmsg(ctf_errno(fp))); + free(args); + return (B_FALSE); + } + + for (i = 0; i < fi.ctc_argc; i++) { + if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { + warnx("failed to obtain type name for argument %u", + i, ctf_errmsg(ctf_errno(fp))); + ret = B_FALSE; + break; + } + + if (strcmp(buf, argv[i]) != 0) { + warnx("argument %u has wrong type: found %s, " + "expected %s", i, buf, argv[i]); + ret = B_FALSE; + break; + } + } + + free(args); + return (ret); +} + +typedef struct ctftest_duplicates { + ctf_file_t *ctd_fp; + char **ctd_names; + size_t ctd_len; + size_t ctd_curent; + boolean_t ctd_ret; +} ctftest_duplicates_t; + +static int +ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg) +{ + char buf[2048]; + ctftest_duplicates_t *dup = arg; + size_t i; + + if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) { + warnx("failed to lookup name for id %ld", id); + dup->ctd_ret = B_FALSE; + return (1); + } + + for (i = 0; i < dup->ctd_curent; i++) { + if (strcmp(buf, dup->ctd_names[i]) == 0) { + warnx("encountered duplicate type '%s'", buf); + dup->ctd_ret = B_FALSE; + /* + * Don't break out of the loop and keep going in case we + * find another duplicate. + */ + return (0); + } + } + + if (dup->ctd_curent == dup->ctd_len) { + char **n; + size_t newlen = dup->ctd_len * 2; + + n = recallocarray(dup->ctd_names, dup->ctd_len, newlen, + sizeof (char *)); + if (n == NULL) { + warnx("failed to resize type name array"); + dup->ctd_ret = B_FALSE; + return (1); + } + + dup->ctd_names = n; + dup->ctd_len = newlen; + } + + dup->ctd_names[dup->ctd_curent] = strdup(buf); + if (dup->ctd_names[dup->ctd_curent] == NULL) { + warn("failed to duplicate type name"); + dup->ctd_ret = B_FALSE; + return (1); + } + dup->ctd_curent++; + + return (0); +} + +boolean_t +ctftest_duplicates(ctf_file_t *fp) +{ + size_t i; + ctftest_duplicates_t d; + + bzero(&d, sizeof (d)); + d.ctd_fp = fp; + d.ctd_len = 4; + d.ctd_ret = B_TRUE; + d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *)); + if (d.ctd_names == NULL) { + warnx("failed to allocate duplicate name storage"); + return (B_FALSE); + } + + (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d); + + for (i = 0; i < d.ctd_curent; i++) { + free(d.ctd_names[i]); + } + free(d.ctd_names); + + return (d.ctd_ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-common.h b/usr/src/test/util-tests/tests/ctf/check-common.h new file mode 100644 index 0000000000..f78fb2f00c --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-common.h @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#ifndef _CHECK_COMMON_H +#define _CHECK_COMMON_H + +/* + * Common definitions for the CTF tests + */ + +#include <stdlib.h> +#include <unistd.h> +#include <libctf.h> +#include <err.h> +#include <strings.h> +#include <sys/param.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct check_number { + const char *cn_tname; + uint_t cn_kind; + uint_t cn_flags; + uint_t cn_offset; + uint_t cn_size; +} check_number_t; + +typedef struct check_symbol { + const char *cs_symbol; + const char *cs_type; +} check_symbol_t; + +typedef struct check_descent { + const char *cd_tname; + uint_t cd_kind; + const char *cd_contents; + uint_t cd_nents; +} check_descent_t; + +typedef struct check_descent_test { + const char *cdt_sym; + const check_descent_t *cdt_tests; +} check_descent_test_t; + +typedef struct check_enum { + const char *ce_name; + int64_t ce_value; +} check_enum_t; + +typedef struct check_enum_test { + const char *cet_type; + const check_enum_t *cet_tests; +} check_enum_test_t; + +typedef struct check_member { + const char *cm_name; + const char *cm_type; + ulong_t cm_offset; +} check_member_t; + +typedef struct check_member_test { + const char *cmt_type; + int cmt_kind; + size_t cmt_size; + const check_member_t *cmt_members; +} check_member_test_t; + +typedef struct check_function_test { + const char *cft_name; + const char *cft_rtype; + uint_t cft_nargs; + uint_t cft_flags; + const char **cft_args; +} check_function_test_t; + +/* + * Looks up each type and verifies that it matches the expected type. + */ +extern boolean_t ctftest_check_numbers(ctf_file_t *, const check_number_t *); + +/* + * Looks at each symbol specified and verifies that it matches the expected + * type. + */ +extern boolean_t ctftest_check_symbols(ctf_file_t *, const check_symbol_t *); + +/* + * Given a symbol name which refers to a type, walks all the references of that + * type and checks against it with each subsequent entry. + */ +extern boolean_t ctftest_check_descent(const char *, ctf_file_t *, + const check_descent_t *); + +/* + * Checks that all of the listed members of an enum are present and have the + * right values. + */ +extern boolean_t ctftest_check_enum(const char *, ctf_file_t *, + const check_enum_t *); + +/* + * Checks that all of the members of a structure or union are present and have + * the right types and byte offsets. This can be used for either structures or + * unions. + */ +extern boolean_t ctftest_check_members(const char *, ctf_file_t *, int, size_t, + const check_member_t *); + +/* + * Check that the named function or function pointer has the correct return + * type, arguments, and function flags. + */ +extern boolean_t ctftest_check_function(const char *, ctf_file_t *, + const char *, uint_t, uint_t, const char **); +extern boolean_t ctftest_check_fptr(const char *, ctf_file_t *, + const char *, uint_t, uint_t, const char **); + +/* + * Determine whether or not we have a duplicate type or not based on its name. + */ +extern boolean_t ctftest_duplicates(ctf_file_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _CHECK_COMMON_H */ diff --git a/usr/src/test/util-tests/tests/ctf/check-enum.c b/usr/src/test/util-tests/tests/ctf/check-enum.c new file mode 100644 index 0000000000..79d6f795ed --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-enum.c @@ -0,0 +1,143 @@ +/* + * 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. + */ + +/* + * Check that we properly handle enums. + */ + +#include "check-common.h" + +static check_symbol_t check_syms[] = { + { "ff6", "enum ff6" }, + { "ff10", "ff10_t" }, + { NULL } +}; + +static check_descent_t check_descent_ff6[] = { + { "enum ff6", CTF_K_ENUM }, + { NULL } +}; + +static check_descent_t check_descent_ff10[] = { + { "ff10_t", CTF_K_TYPEDEF }, + { "enum ff10", CTF_K_ENUM }, + { NULL } +}; + +static check_descent_t check_descent_chrono[] = { + { "chrono_t", CTF_K_TYPEDEF }, + { "enum chrono", CTF_K_ENUM }, + { NULL } +}; + +static check_descent_test_t descents[] = { + { "ff10", check_descent_ff10 }, + { "ff6", check_descent_ff6 }, + { "trigger", check_descent_chrono }, + { NULL } +}; + +static check_enum_t check_enum_ff6[] = { + { "TERRA", 0 }, + { "LOCKE", 1 }, + { "EDGAR", 2 }, + { "SABIN", 3 }, + { "CELES", 4 }, + { "CYAN", 5 }, + { "SHADOW", 6 }, + { "GAU", 7 }, + { "SETZER", 8 }, + { "STRAGO", 9 }, + { "RELM", 10 }, + { "MOG", 11 }, + { "GOGO", 12 }, + { "UMARO", 13 }, + { "LEO", 14 }, + { "KEFKA", 15 }, + { NULL } +}; + +static check_enum_t check_enum_ff10[] = { + { "TIDUS", -10 }, + { "YUNA", 23 }, + { "AURON", -34 }, + { "WAKA", 52 }, + { "LULU", INT32_MAX }, + { "RIKKU", INT32_MIN }, + { "KHIMARI", 0 }, + { NULL } +}; + +static check_enum_t check_enum_chrono[] = { + { "CRONO", 0x1000 }, + { "LUCCA", 0x2000 }, + { "MARLE", 0x3000 }, + { "FROG", 0x4000 }, + { "ROBO", 0x5000 }, + { "AYLA", 0x6000 }, + { "MAGUS", 0x7000 }, + { "SCHALA", 0x8000 }, + { "LAVOS", 0x9000 }, + { "BALTHAZAR", 0xa000 }, + { NULL } +}; + +static check_enum_test_t enums[] = { + { "enum ff6", check_enum_ff6 }, + { "enum ff10", check_enum_ff10 }, + { "enum chrono", check_enum_chrono }, + { NULL } +}; + +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 d; + + 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 (d = 0; descents[d].cdt_sym != NULL; d++) { + if (!ctftest_check_descent(descents[d].cdt_sym, fp, + descents[d].cdt_tests)) { + ret = EXIT_FAILURE; + } + } + + for (d = 0; enums[d].cet_type != NULL; d++) { + if (!ctftest_check_enum(enums[d].cet_type, fp, + enums[d].cet_tests)) { + ret = EXIT_FAILURE; + } + } + ctf_close(fp); + } + + return (ret); + +} diff --git a/usr/src/test/util-tests/tests/ctf/check-float.c b/usr/src/test/util-tests/tests/ctf/check-float.c new file mode 100644 index 0000000000..948c467446 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-float.c @@ -0,0 +1,80 @@ +/* + * 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. + */ + +/* + * Check for basic float types. + */ + +#include <stdlib.h> +#include <unistd.h> + +#include "check-common.h" + +static check_number_t check_floats[] = { + { "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 }, + { "double", CTF_K_FLOAT, CTF_FP_DOUBLE, 0, 64 }, +#ifdef TARGET_LP64 + { "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 128 }, +#else + { "long double", CTF_K_FLOAT, CTF_FP_LDOUBLE, 0, 96 }, +#endif + { "complex float", CTF_K_FLOAT, CTF_FP_CPLX, 0, 64 }, + { "complex double", CTF_K_FLOAT, CTF_FP_DCPLX, 0, 128 }, +#ifdef TARGET_LP64 + { "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 256 }, +#else + { "complex long double", CTF_K_FLOAT, CTF_FP_LDCPLX, 0, 192 }, +#endif + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "a", "float" }, + { "b", "double" }, + { "c", "long double" }, + { "d", "complex float" }, + { "e", "complex double" }, + { "f", "complex long double" }, + { NULL } +}; + +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; + + 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_numbers(fp, check_floats)) + ret = EXIT_FAILURE; + if (!ctftest_check_symbols(fp, check_syms)) + ret = EXIT_FAILURE; + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-forward.c b/usr/src/test/util-tests/tests/ctf/check-forward.c new file mode 100644 index 0000000000..2b00209fce --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-forward.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + +/* + * Verify that we can properly handle forward declarations. + * + * In test-forward.c barp is declared as a union, not a struct. However, today + * the CTF tooling does not contain enough information to know whether a forward + * declaration was for a struct or a union, only that it was a forward. + * Therefore, the type printing information assumes at the moment that the type + * is a struct. In a future revision of the CTF type data, we should encode this + * information in the equivalent of ctt_info so we can properly distinguish + * between these. + */ + +#include "check-common.h" + +static check_symbol_t check_syms[] = { + { "forward", "struct forward" }, + { "foop", "struct foo *" }, + { "barp", "struct bar *" }, + { "bazp", "enum baz *" }, + { NULL } +}; + +static check_member_t check_member_forward[] = { +#ifdef TARGET_LP64 + { "prev", "struct foo *", 0 }, + { "next", "struct foo *", 8 * NBBY }, + { "data", "struct bar *", 16 * NBBY }, + { "tag", "enum baz *", 24 * NBBY }, +#else + { "prev", "struct foo *", 0 }, + { "next", "struct foo *", 4 * NBBY }, + { "data", "struct bar *", 8 * NBBY }, + { "tag", "enum baz *", 12 * NBBY }, +#endif + { NULL } +}; + + +static check_member_test_t members[] = { +#ifdef TARGET_LP64 + { "struct forward", CTF_K_STRUCT, 32, check_member_forward }, +#else + { "struct forward", CTF_K_STRUCT, 16, check_member_forward }, +#endif + { NULL } +}; + +static check_descent_t check_descent_foo[] = { + { "struct foo *", CTF_K_POINTER }, + { "struct foo", CTF_K_FORWARD }, + { NULL } +}; + +static check_descent_t check_descent_bar[] = { + { "struct bar *", CTF_K_POINTER }, + { "struct bar", CTF_K_FORWARD }, + { NULL } +}; + +static check_descent_t check_descent_baz[] = { + { "enum baz *", CTF_K_POINTER }, + { "enum baz", CTF_K_ENUM }, + { NULL } +}; + +static check_descent_test_t descents[] = { + { "foop", check_descent_foo }, + { "barp", check_descent_bar }, + { "bazp", check_descent_baz }, + { NULL } +}; +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; descents[j].cdt_sym != NULL; j++) { + if (!ctftest_check_descent(descents[j].cdt_sym, fp, + descents[j].cdt_tests)) { + 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; + } + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-function.c b/usr/src/test/util-tests/tests/ctf/check-function.c new file mode 100644 index 0000000000..fdb60ce290 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-function.c @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * Check that we properly handle functions and function pointers. + */ + +#include "check-common.h" + +static const char *one_args[] = { "int" }; +static const char *two_args[] = { "int", "const char *" }; +static const char *three_args[] = { "int", "const char *", "float" }; +static const char *argument_args[] = { "uintptr_t" }; +static const char *vararg_args[] = { "const char *" }; + +static check_function_test_t functions[] = { + { "simple_func", "void", 0, 0, NULL }, + { "one", "void", 1, 0, one_args }, + { "two", "void", 2, 0, two_args }, + { "three", "void", 3, 0, three_args }, + { "noarg", "const char *", 0, 0, NULL }, + { "argument", "const char *", 1, 0, argument_args }, + { "vararg", "void", 1, CTF_FUNC_VARARG, vararg_args }, + { "vararg_ret", "uintptr_t", 1, CTF_FUNC_VARARG, vararg_args }, + { NULL } +}; + +static const char *strfunc_args[] = { "const char *", "const char *" }; + +static check_function_test_t fptrs[] = { + { "strfunc_t", "int", 2, 0, strfunc_args }, + { "vararg_t", "void", 1, CTF_FUNC_VARARG, vararg_args }, + { NULL } +}; + +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; + } + + for (j = 0; functions[j].cft_name != NULL; j++) { + if (!ctftest_check_function(functions[j].cft_name, fp, + functions[j].cft_rtype, functions[j].cft_nargs, + functions[j].cft_flags, functions[j].cft_args)) { + ret = EXIT_FAILURE; + } + } + + for (j = 0; fptrs[j].cft_name != NULL; j++) { + if (!ctftest_check_fptr(fptrs[j].cft_name, fp, + fptrs[j].cft_rtype, fptrs[j].cft_nargs, + fptrs[j].cft_flags, fptrs[j].cft_args)) { + ret = EXIT_FAILURE; + } + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-int.c b/usr/src/test/util-tests/tests/ctf/check-int.c new file mode 100644 index 0000000000..ac34f27e85 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-int.c @@ -0,0 +1,88 @@ +/* + * 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. + */ + +/* + * Check for basic integer types. + */ + +#include <stdlib.h> +#include <unistd.h> + +#include "check-common.h" + +static check_number_t check_ints[] = { + { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, + { "short", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 16 }, + { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 }, +#ifdef TARGET_LP64 + { "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 }, +#else + { "long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 }, +#endif + { "long long", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 64 }, + { "unsigned char", CTF_K_INTEGER, CTF_INT_CHAR, 0, 8 }, + { "unsigned short", CTF_K_INTEGER, 0, 0, 16 }, + { "unsigned int", CTF_K_INTEGER, 0, 0, 32 }, +#ifdef TARGET_LP64 + { "unsigned long", CTF_K_INTEGER, 0, 0, 64 }, +#else + { "unsigned long", CTF_K_INTEGER, 0, 0, 32 }, +#endif + { "unsigned long long", CTF_K_INTEGER, 0, 0, 64 }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "a", "char" }, + { "b", "unsigned char" }, + { "d", "short" }, + { "e", "unsigned short" }, + { "g", "int" }, + { "h", "unsigned int" }, + { "j", "long" }, + { "k", "unsigned long" }, + { "m", "long long" }, + { "n", "unsigned long long" }, + { NULL }, +}; + +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; + + 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_numbers(fp, check_ints)) + ret = EXIT_FAILURE; + if (!ctftest_check_symbols(fp, check_syms)) + ret = EXIT_FAILURE; + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c new file mode 100644 index 0000000000..06db2ad1f0 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-merge-dedup.c @@ -0,0 +1,82 @@ +/* + * 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 we don't end up with several copies of the same type. + */ + +#include "check-common.h" + +static check_symbol_t check_syms[] = { + { "int", "a" }, + { "short", "b" }, + { "const char *", "c" }, + { "float", "d" }, + { "double" "e" }, + { "int", "f" }, + { "short", "g" }, + { "const char *", "h" }, + { "float", "i" }, + { "double" "j" }, + { "int", "k" }, + { "short", "l" }, + { "const char *", "m" }, + { "float", "n" }, + { "double" "o" }, + { "int", "p" }, + { "short", "q" }, + { "const char *", "r" }, + { "float", "s" }, + { "double" "t" }, + { "struct dup" "dupmain" }, + { "struct dup" "dup1" }, + { "struct dup" "dup2" }, + { "struct dup" "dup3" }, + { NULL } +}; + + +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; + + 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; + } + + if (!ctftest_duplicates(fp)) { + ret = EXIT_FAILURE; + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-forward.c b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c new file mode 100644 index 0000000000..e396beb133 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-merge-forward.c @@ -0,0 +1,132 @@ +/* + * 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); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c new file mode 100644 index 0000000000..86b688bc0b --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-merge-reduction.c @@ -0,0 +1,72 @@ +/* + * 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 global that has been scoped to local scope through symbol + * reduction of a mapfile can still be detected. + */ + +#include "check-common.h" + +static check_symbol_t check_syms[] = { + { "data", "int" }, + { NULL } +}; + +static const char *scoped_args[] = { "uint32_t" }; + +static check_function_test_t functions[] = { + { "global", "int", 0, 0, NULL }, + { "scoped", "int", 1, 0, scoped_args }, + { NULL } +}; + +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; functions[j].cft_name != NULL; j++) { + if (!ctftest_check_function(functions[j].cft_name, fp, + functions[j].cft_rtype, functions[j].cft_nargs, + functions[j].cft_flags, functions[j].cft_args)) { + ret = EXIT_FAILURE; + } + } + + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-static.c b/usr/src/test/util-tests/tests/ctf/check-merge-static.c new file mode 100644 index 0000000000..3ca40eb5aa --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-merge-static.c @@ -0,0 +1,290 @@ +/* + * 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. + */ + +/* + * Verify that various type information for static symbols is accurate for the + * file in question. To run this test, there's a global and static version of a + * symbol and function that exists on a per-file basis. These will all have been + * reproduced in the output file. As such, we need to iterate the symbol table + * to know which version should be which and use that to drive things. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <libelf.h> +#include <gelf.h> +#include <limits.h> +#include <strings.h> + +#include "check-common.h" + +typedef struct check_map { + const char *map_file; + const char *map_type; +} check_map_t; + +static const char *global_type = "int"; +static check_map_t map[] = { + { "test-a.c", "uint8_t" }, + { "test-b.c", "uint16_t" }, + { "test-c.c", "uint32_t" }, + { "test-d.c", "uint64_t" }, + { NULL } +}; + +static const char * +check_file_to_type(GElf_Sym *symp, const char *file, const char *name) +{ + uint_t i; + + if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL) { + return (global_type); + } + + if (file == NULL) { + warnx("encountered non-global symbol without STT_FILE info: %s", + name); + return (NULL); + } + + for (i = 0; map[i].map_file != NULL; i++) { + if (strcmp(map[i].map_file, file) == 0) { + return (map[i].map_type); + } + } + + warnx("failed to find type mapping for symbol %s, file %s", name, file); + return (NULL); +} + +static int +check_global(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file, + const char *name) +{ + const char *type; + ctf_id_t tid; + char buf[2048]; + + if ((type = check_file_to_type(symp, file, name)) == NULL) { + return (EXIT_FAILURE); + } + + if ((tid = ctf_lookup_by_symbol(fp, symid)) == CTF_ERR) { + warnx("failed to get type for symbol %s (%d): %s", name, symid, + ctf_errmsg(ctf_errno(fp))); + return (EXIT_FAILURE); + } + + if (ctf_type_name(fp, tid, buf, sizeof (buf)) == NULL) { + warnx("failed to get type name for symbol %s (%d): %s", + name, symid, ctf_errmsg(ctf_errno(fp))); + return (EXIT_FAILURE); + } + + if (strcmp(buf, type) != 0) { + warnx("type mismatch for symbol %s (%d): found %s, expected %s", + name, symid, buf, type); + return (EXIT_FAILURE); + } + + return (0); +} + +static int +check_mumble(ctf_file_t *fp, GElf_Sym *symp, int symid, const char *file, + const char *name) +{ + const char *type; + ctf_funcinfo_t fi; + ctf_id_t id, args; + + if ((type = check_file_to_type(symp, file, name)) == NULL) { + return (EXIT_FAILURE); + } + + if ((id = ctf_lookup_by_name(fp, type)) == CTF_ERR) { + warnx("failed to lookup type id for %s: %s", type, + ctf_errmsg(ctf_errno(fp))); + return (EXIT_FAILURE); + } + + if (ctf_func_info(fp, symid, &fi) != 0) { + warnx("failed to get function information for %s (%d): %s", + name, symid, ctf_errmsg(ctf_errno(fp))); + return (EXIT_FAILURE); + } + + if (fi.ctc_argc != 1) { + warnx("argument count mismatch for symbol %s (%d): found %u, " + "expected %d", name, symid, fi.ctc_argc, 1); + return (EXIT_FAILURE); + } + + if (fi.ctc_flags != 0) { + warnx("function flags mismatch for symbol %s (%d): found %u, " + "expected %d", name, symid, fi.ctc_flags, 0); + return (EXIT_FAILURE); + } + + if (fi.ctc_return != id) { + warnx("return value mismatch for symbol %s (%d): found %ld, " + "expected %ld", name, symid, fi.ctc_return, id); + return (EXIT_FAILURE); + } + + if (ctf_func_args(fp, symid, 1, &args) != 0) { + warnx("failed to get function arguments for symbol %s (%d): %s", + name, symid, ctf_errmsg(ctf_errno(fp))); + return (EXIT_FAILURE); + } + + if (args != id) { + warnx("argument mismatch for symbol %s (%d): found %ld, " + "expected %ld", name, symid, args, id); + return (EXIT_FAILURE); + } + + return (0); +} + +static int +check_merge_static(const char *file, ctf_file_t *fp, Elf *elf) +{ + Elf_Scn *scn = NULL, *symscn = NULL; + Elf_Data *symdata = NULL; + GElf_Shdr symhdr; + ulong_t nsyms; + int i; + const char *curfile = NULL; + int ret = 0; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &symhdr) == NULL) { + warnx("failed to get section header: %s", + elf_errmsg(elf_errno())); + return (EXIT_FAILURE); + } + + if (symhdr.sh_type == SHT_SYMTAB) { + symscn = scn; + break; + } + } + + if (symscn == NULL) { + warnx("failed to find symbol table for %s", file); + return (EXIT_FAILURE); + } + + if ((symdata = elf_getdata(symscn, NULL)) == NULL) { + warnx("failed to get data for symbol table %s: %s", file, + elf_errmsg(elf_errno())); + return (EXIT_FAILURE); + } + + if (symhdr.sh_link == SHN_XINDEX) { + warnx("test does not support extended ELF sections!"); + return (EXIT_FAILURE); + } + nsyms = symhdr.sh_size / symhdr.sh_entsize; + if (nsyms > INT_MAX) { + warnx("file contains more symbols than libelf can iterate"); + return (EXIT_FAILURE); + } + + for (i = 1; i < (int)nsyms; i++) { + GElf_Sym sym; + const char *name; + uint_t type; + + if (gelf_getsym(symdata, i, &sym) == NULL) { + warnx("failed to get data about symbol %d", i); + return (EXIT_FAILURE); + } + + if ((name = elf_strptr(elf, symhdr.sh_link, sym.st_name)) == + NULL) { + warnx("failed to get name for symbol %d", i); + return (EXIT_FAILURE); + } + + type = GELF_ST_TYPE(sym.st_info); + if (type == STT_FILE) { + curfile = name; + continue; + } + + if (strcmp(name, "global") == 0) { + ret |= check_global(fp, &sym, i, curfile, name); + } else if (strcmp(name, "mumble") == 0) { + ret |= check_mumble(fp, &sym, i, curfile, name); + } + } + + return (ret); +} + +int +main(int argc, char *argv[]) +{ + int i, ret = 0; + + if (argc < 2) { + errx(EXIT_FAILURE, "missing test files"); + } + + if (elf_version(EV_CURRENT) == EV_NONE) { + errx(EXIT_FAILURE, "failed to initialize libelf"); + } + + for (i = 1; i < argc; i++) { + int fd; + ctf_file_t *fp; + Elf *elf; + + if ((fd = open(argv[i], O_RDONLY)) < 0) { + warn("failed to open %s", argv[i]); + ret = EXIT_FAILURE; + continue; + } + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + warnx("failed to open libelf handle to %s", argv[i]); + ret = EXIT_FAILURE; + (void) close(fd); + continue; + } + + if ((fp = ctf_open(argv[i], &ret)) == NULL) { + warnx("failed to open %s: %s", argv[i], + ctf_errmsg(ret)); + ret = EXIT_FAILURE; + (void) close(fd); + (void) elf_end(elf); + continue; + } + + if (check_merge_static(argv[i], fp, elf) != 0) { + ret = EXIT_FAILURE; + } + + ctf_close(fp); + (void) close(fd); + (void) elf_end(elf); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-merge-weak.c b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c new file mode 100644 index 0000000000..da6d37def8 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-merge-weak.c @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/* + * Check that we properly handle weak symbols. + */ + +#include "check-common.h" + + +static check_function_test_t functions[] = { + { "mumble", "int", 0, 0, NULL }, + { "_mumble", "int", 0, 0, NULL }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "foo", "int" }, + { "_foo", "int" }, + { NULL } +}; + +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; functions[j].cft_name != NULL; j++) { + if (!ctftest_check_function(functions[j].cft_name, fp, + functions[j].cft_rtype, functions[j].cft_nargs, + functions[j].cft_flags, functions[j].cft_args)) { + ret = EXIT_FAILURE; + } + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-reference.c b/usr/src/test/util-tests/tests/ctf/check-reference.c new file mode 100644 index 0000000000..05c0469c15 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-reference.c @@ -0,0 +1,197 @@ +/* + * 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. + */ + +/* + * Check that we properly understand reference types and can walk through them + * as well as generate them. + */ + +#include "check-common.h" + +static check_number_t check_base[] = { + { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, + { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 }, + { "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "a", "int" }, + { "aa", "test_int_t" }, + { "b", "const short" }, + { "c", "volatile float" }, + { "d", "int *" }, + { "dd", "int **" }, + { "ddd", "int ***" }, + { "e", "test_int_t *" }, + { "ce", "const test_int_t *" }, + { "ve", "volatile test_int_t *" }, + { "cve", "const volatile test_int_t *" }, + { "f", "int *const *" }, + { "g", "const char *const" }, + { NULL }, +}; + +static check_descent_t check_descent_aa[] = { + { "test_int_t", CTF_K_TYPEDEF }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_b[] = { + { "const short", CTF_K_CONST }, + { "short", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_c[] = { + { "volatile float", CTF_K_VOLATILE }, + { "float", CTF_K_FLOAT }, + { NULL } +}; + +static check_descent_t check_descent_d[] = { + { "int *", CTF_K_POINTER }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_dd[] = { + { "int **", CTF_K_POINTER }, + { "int *", CTF_K_POINTER }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_ddd[] = { + { "int ***", CTF_K_POINTER }, + { "int **", CTF_K_POINTER }, + { "int *", CTF_K_POINTER }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_e[] = { + { "test_int_t *", CTF_K_POINTER }, + { "test_int_t", CTF_K_TYPEDEF }, + { "int", CTF_K_INTEGER }, + { NULL }, +}; + +static check_descent_t check_descent_ce[] = { + { "const test_int_t *", CTF_K_POINTER }, + { "const test_int_t", CTF_K_CONST }, + { "test_int_t", CTF_K_TYPEDEF }, + { "int", CTF_K_INTEGER }, + { NULL }, +}; + +static check_descent_t check_descent_ve[] = { + { "volatile test_int_t *", CTF_K_POINTER}, + { "volatile test_int_t", CTF_K_VOLATILE }, + { "test_int_t", CTF_K_TYPEDEF }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_cve[] = { + { "const volatile test_int_t *", CTF_K_POINTER }, + { "const volatile test_int_t", CTF_K_CONST }, + { "volatile test_int_t", CTF_K_VOLATILE }, + { "test_int_t", CTF_K_TYPEDEF }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_f[] = { + { "int *const *", CTF_K_POINTER }, + { "int *const", CTF_K_CONST }, + { "int *", CTF_K_POINTER }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_g[] = { + { "const char *const", CTF_K_CONST }, + { "const char *", CTF_K_POINTER }, + { "const char", CTF_K_CONST }, + { "char", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_t check_descent_cvh[] = { + { "const volatile foo_t *", CTF_K_POINTER }, + { "const volatile foo_t", CTF_K_CONST }, + { "volatile foo_t", CTF_K_VOLATILE }, + { "foo_t", CTF_K_TYPEDEF }, + { "int *const *", CTF_K_POINTER }, + { "int *const", CTF_K_CONST }, + { "int *", CTF_K_POINTER }, + { "int", CTF_K_INTEGER }, + { NULL } +}; + +static check_descent_test_t descents[] = { + { "aa", check_descent_aa }, + { "b", check_descent_b }, + { "c", check_descent_c }, + { "d", check_descent_d }, + { "dd", check_descent_dd }, + { "ddd", check_descent_ddd }, + { "e", check_descent_e }, + { "ce", check_descent_ce }, + { "ve", check_descent_ve }, + { "cve", check_descent_cve }, + { "f", check_descent_f }, + { "g", check_descent_g }, + { "cvh", check_descent_cvh }, + { NULL } +}; + +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 d; + + 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_numbers(fp, check_base)) + ret = EXIT_FAILURE; + if (!ctftest_check_symbols(fp, check_syms)) + ret = EXIT_FAILURE; + for (d = 0; descents[d].cdt_sym != NULL; d++) { + if (!ctftest_check_descent(descents[d].cdt_sym, fp, + descents[d].cdt_tests)) { + ret = EXIT_FAILURE; + } + } + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-sou.c b/usr/src/test/util-tests/tests/ctf/check-sou.c new file mode 100644 index 0000000000..32bcc20b6d --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-sou.c @@ -0,0 +1,405 @@ +/* + * 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. + */ + +/* + * Check that we properly handle structures and unions. + */ + +#include "check-common.h" + +static check_number_t check_bitfields[] = { +#ifdef TARGET_LP64 + { "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 }, + { "unsigned long:2", CTF_K_INTEGER, 0, 0, 2 }, + { "unsigned long:4", CTF_K_INTEGER, 0, 0, 4 }, + { "unsigned long:5", CTF_K_INTEGER, 0, 0, 5 }, + { "unsigned long:8", CTF_K_INTEGER, 0, 0, 8 }, + { "unsigned long:16", CTF_K_INTEGER, 0, 0, 16 }, + { "unsigned long:19", CTF_K_INTEGER, 0, 0, 19 }, + { "unsigned long:32", CTF_K_INTEGER, 0, 0, 32 }, +#else + { "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 }, + { "unsigned long long:2", CTF_K_INTEGER, 0, 0, 2 }, + { "unsigned long long:4", CTF_K_INTEGER, 0, 0, 4 }, + { "unsigned long long:5", CTF_K_INTEGER, 0, 0, 5 }, + { "unsigned long long:8", CTF_K_INTEGER, 0, 0, 8 }, + { "unsigned long long:16", CTF_K_INTEGER, 0, 0, 16 }, + { "unsigned long long:19", CTF_K_INTEGER, 0, 0, 19 }, + { "unsigned long long:32", CTF_K_INTEGER, 0, 0, 32 }, +#endif + { "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 }, + { "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 }, + { "unsigned int:32", CTF_K_INTEGER, 0, 0, 32 }, + { "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "foo", "struct foo" }, + { "head", "nlist_t" }, + { "forward", "const forward_t" }, + { "oot", "struct round_up" }, + { "botw", "struct fixed_up" }, + { "sophie", "struct mysterious_barrel" }, + { "ayesha", "struct dusk_barrel" }, + { "stats", "struct stats" }, + { "ring", "struct fellowship" }, + { "rings", "struct rings" }, + { "nvme", "struct csts" }, + { "games", "union jrpg" }, + { "nier", "union nier" }, + { "kh", "union kh" }, + { "ct", "struct trigger" }, + { "regress", "const union regress [9]" }, + { NULL } +}; + +static check_member_t check_member_foo[] = { + { "a", "int", 0 }, + { "b", "float", 4 * NBBY }, + { "c", "const char *", 8 * NBBY }, + { NULL } +}; + +static check_member_t check_member_node[] = { + { "prev", "struct node *", 0 }, +#ifdef TARGET_LP64 + { "next", "struct node *", 8 * NBBY }, +#else + { "next", "struct node *", 4 * NBBY }, +#endif + { NULL } +}; + +static check_member_t check_member_nlist[] = { + { "size", "size_t", 0 }, +#ifdef TARGET_LP64 + { "off", "size_t", 8 * NBBY }, + { "head", "struct node", 16 * NBBY }, +#else + { "off", "size_t", 4 * NBBY }, + { "head", "struct node", 8 * NBBY }, +#endif + { NULL } +}; + +static check_member_t check_member_forward[] = { + { "past", "void *", 0 }, +#ifdef TARGET_LP64 + { "present", "void *", 8 * NBBY }, + { "future", "void *", 16 * NBBY }, +#else + { "present", "void *", 4 * NBBY }, + { "future", "void *", 8 * NBBY }, +#endif + { NULL } +}; + +static check_member_t check_member_round_up[] = { + { "triforce", "uint8_t", 0 }, + { "link", "uint32_t", 4 * NBBY }, + { "zelda", "uint8_t", 8 * NBBY }, + { "ganon", "uint8_t", 9 * NBBY }, + { NULL } +}; + +static check_member_t check_member_fixed_up[] = { + { "triforce", "uint8_t", 0 }, + { "link", "uint32_t", 1 * NBBY }, + { "zelda", "uint8_t", 5 * NBBY }, + { "ganon", "uint8_t", 6 * NBBY }, + { NULL } +}; + +#ifdef TARGET_LP64 +static check_member_t check_member_component[] = { + { "m", "enum material", 0 }, + { "grade", "uint64_t", 8 * NBBY }, + { "count", "uint64_t", 16 * NBBY }, + { "locations", "const char *[4]", 24 * NBBY }, + { NULL } +}; + +static check_member_t check_member_mysterious[] = { + { "name", "const char *", 0 }, + { "capacity", "size_t", 8 * NBBY }, + { "optional", "struct component [0]", 16 * NBBY }, + { NULL } +}; + +static check_member_t check_member_dusk[] = { + { "name", "const char *", 0 }, + { "opacity", "size_t", 8 * NBBY }, + { "optional", "struct component [0]", 16 * NBBY }, + { NULL } +}; + + +static check_member_t check_member_stats[] = { + { "hp", "unsigned long:16", 0 }, + { "mp", "unsigned long:16", 16 }, + { "str", "unsigned long:8", 32 }, + { "dex", "unsigned long:4", 40 }, + { "con", "unsigned long:1", 44 }, + { "inte", "unsigned long:2", 45 }, + { "wis", "unsigned long:1", 47 }, + { "cha", "unsigned long:4", 48 }, + { "sanity", "unsigned long:1", 52 }, + { "attack", "unsigned long:2", 53 }, + { "mattack", "unsigned long:1", 55 }, + { "defense", "unsigned long:8", 56 }, + { "mdefense", "unsigned long:32", 64 }, + { "evasion", "unsigned long:8", 96 }, + { "crit", "unsigned long:5", 104 }, + { "luck", "unsigned long:19", 109 }, + { NULL } +}; +#else +static check_member_t check_member_component[] = { + { "m", "enum material", 0 }, + { "grade", "uint64_t", 4 * NBBY }, + { "count", "uint64_t", 12 * NBBY }, + { "locations", "const char *[4]", 20 * NBBY }, + { NULL } +}; + +static check_member_t check_member_mysterious[] = { + { "name", "const char *", 0 }, + { "capacity", "size_t", 4 * NBBY }, + { "optional", "struct component [0]", 8 * NBBY }, + { NULL } +}; + +static check_member_t check_member_dusk[] = { + { "name", "const char *", 0 }, + { "opacity", "size_t", 4 * NBBY }, + { "optional", "struct component [0]", 8 * NBBY }, + { NULL } +}; + + +static check_member_t check_member_stats[] = { + { "hp", "unsigned long long:16", 0 }, + { "mp", "unsigned long long:16", 16 }, + { "str", "unsigned long long:8", 32 }, + { "dex", "unsigned long long:4", 40 }, + { "con", "unsigned long long:1", 44 }, + { "inte", "unsigned long long:2", 45 }, + { "wis", "unsigned long long:1", 47 }, + { "cha", "unsigned long long:4", 48 }, + { "sanity", "unsigned long long:1", 52 }, + { "attack", "unsigned long long:2", 53 }, + { "mattack", "unsigned long long:1", 55 }, + { "defense", "unsigned long long:8", 56 }, + { "mdefense", "unsigned long long:32", 64 }, + { "evasion", "unsigned long long:8", 96 }, + { "crit", "unsigned long long:5", 104 }, + { "luck", "unsigned long long:19", 109 }, + { NULL } +}; +#endif + +static check_member_t check_member_fellowship[] = { + { "frodo", "unsigned short:1", 0 }, + { "sam", "unsigned short:1", 1 }, + { "merry", "unsigned short:1", 2 }, + { "pippin", "unsigned short:1", 3 }, + { "aragorn", "unsigned short:1", 4 }, + { "boromir", "unsigned short:1", 5 }, + { "legolas", "unsigned short:1", 6 }, + { "gimli", "unsigned short:1", 7 }, + { "gandalf", "unsigned short:1", 8 }, + { NULL } +}; + +static check_member_t check_member_rings[] = { + { "elves", "unsigned int:3", 0 }, + { "dwarves", "unsigned int:7", 3 }, + { "men", "unsigned int:9", 10 }, + { "one", "uint8_t", 3 * NBBY }, + { "silmarils", "uint8_t [3]", 4 * NBBY }, + { NULL } +}; + +static check_member_t check_member_csts[] = { + { "rdy", "unsigned int:7", 0 }, + { "csts", "unsigned int:32", 7 }, + { NULL } +}; + +static check_member_t check_member_jrpg[] = { + { "ff", "int", 0 }, + { "atelier", "double [4]", 0 }, + { "tales", "const char *", 0 }, + { "chrono", "int (*)()", 0 }, + { "xeno", "struct rings", 0 }, + { NULL } +}; + +static check_member_t check_member_android[] = { + { "_2b", "unsigned int:16", 0 }, + { "_9s", "unsigned int:16", 16 }, + { NULL } +}; + +static check_member_t check_member_nier[] = { + { "automata", "uint32_t", 0 }, + { "android", "struct android", 0 }, + { NULL } +}; + +static check_member_t check_member_kh[] = { + { "sora", "int:3", 0 }, + { "riku", "char:7", 0 }, + { "kairi", "double", 0 }, + { "namine", "complex double", 0 }, + { NULL } +}; + +static check_member_t check_member_trigger[] = { + { "chrono", "uint8_t", 0 }, + { "cross", "uint8_t", 8 }, + /* + * This test has an anonymous union. Unfortunately, there's not a great + * way to distinguish between various anonymous unions in this form. + */ +#ifdef TARGET_LP64 + { "", "union ", 64 }, +#else + { "", "union ", 32 }, +#endif + { NULL } +}; + +static check_member_t check_member_regress[] = { + { "i", "unsigned int [3]", 0 }, + { "e", "long double", 0 }, + { NULL } +}; + +static check_member_test_t members[] = { +#ifdef TARGET_LP64 + { "struct foo", CTF_K_STRUCT, 16, check_member_foo }, + { "struct node", CTF_K_STRUCT, 16, check_member_node }, + { "struct nlist", CTF_K_STRUCT, 32, check_member_nlist }, + { "struct forward", CTF_K_STRUCT, 24, check_member_forward }, +#else + { "struct foo", CTF_K_STRUCT, 12, check_member_foo }, + { "struct node", CTF_K_STRUCT, 8, check_member_node }, + { "struct nlist", CTF_K_STRUCT, 16, check_member_nlist }, + { "struct forward", CTF_K_STRUCT, 12, check_member_forward }, +#endif + { "struct round_up", CTF_K_STRUCT, 12, check_member_round_up }, + { "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up }, +#ifdef TARGET_LP64 + { "struct component", CTF_K_STRUCT, 56, check_member_component }, + { "struct mysterious_barrel", CTF_K_STRUCT, 16, + check_member_mysterious }, + { "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk }, +#else + { "struct component", CTF_K_STRUCT, 36, check_member_component }, + { "struct mysterious_barrel", CTF_K_STRUCT, 8, + check_member_mysterious }, + { "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk }, +#endif + { "struct stats", CTF_K_STRUCT, 16, check_member_stats }, + { "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship }, + { "struct rings", CTF_K_STRUCT, 8, check_member_rings }, + { "struct csts", CTF_K_STRUCT, 5, check_member_csts }, + { "union jrpg", CTF_K_UNION, 32, check_member_jrpg }, + { "struct android", CTF_K_STRUCT, 4, check_member_android }, + { "union nier", CTF_K_UNION, 4, check_member_nier }, + { "union kh", CTF_K_UNION, 16, check_member_kh }, +#ifdef TARGET_LP64 + { "struct trigger", CTF_K_STRUCT, 32, check_member_trigger }, + { "union regress", CTF_K_UNION, 16, check_member_regress }, +#else + { "struct trigger", CTF_K_STRUCT, 28, check_member_trigger }, + { "union regress", CTF_K_UNION, 12, check_member_regress }, +#endif + { NULL } +}; + +static check_descent_t check_descent_head[] = { + { "nlist_t", CTF_K_TYPEDEF }, + { "struct nlist", CTF_K_STRUCT }, + { NULL } +}; + +static check_descent_t check_descent_forward[] = { + { "const forward_t", CTF_K_CONST }, + { "forward_t", CTF_K_TYPEDEF }, + { "struct forward", CTF_K_STRUCT }, + { NULL } +}; + +static check_descent_t check_descent_regress[] = { + { "const union regress [9]", CTF_K_CONST }, + { "union regress [9]", CTF_K_ARRAY, "union regress", 9 }, + { "union regress", CTF_K_UNION }, + { NULL } +}; + +static check_descent_test_t descents[] = { + { "head", check_descent_head }, + { "forward", check_descent_forward }, + { "regress", check_descent_regress }, + { NULL } +}; + +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_numbers(fp, check_bitfields)) + ret = EXIT_FAILURE; + if (!ctftest_check_symbols(fp, check_syms)) + ret = EXIT_FAILURE; + for (j = 0; descents[j].cdt_sym != NULL; j++) { + if (!ctftest_check_descent(descents[j].cdt_sym, fp, + descents[j].cdt_tests)) { + 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; + } + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/check-weak.c b/usr/src/test/util-tests/tests/ctf/check-weak.c new file mode 100644 index 0000000000..13e69e87de --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/check-weak.c @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/* + * Check that we properly handle weak symbols. + */ + +#include "check-common.h" + + +static check_function_test_t functions[] = { + { "mumble", "int", 0, 0, NULL }, + { "_mumble", "int", 0, 0, NULL }, + { NULL } +}; + +static check_symbol_t check_syms[] = { + { "strong", "int" }, + { "_strong", "int" }, + { NULL } +}; + +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; functions[j].cft_name != NULL; j++) { + if (!ctftest_check_function(functions[j].cft_name, fp, + functions[j].cft_rtype, functions[j].cft_nargs, + functions[j].cft_flags, functions[j].cft_args)) { + ret = EXIT_FAILURE; + } + } + + ctf_close(fp); + } + + return (ret); +} diff --git a/usr/src/test/util-tests/tests/ctf/ctftest.ksh b/usr/src/test/util-tests/tests/ctf/ctftest.ksh new file mode 100644 index 0000000000..62f5cc5dd7 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/ctftest.ksh @@ -0,0 +1,257 @@ +#!/usr/bin/ksh +# +# +# 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. +# + +# +# Run all of the various CTF tests +# + +unalias -a +#set -o xtrace + +if [[ -z "$TMPDIR" ]]; then + TMPDIR="/tmp" +fi + +ctf_arg0=$(basename $0) +ctf_root=$(cd $(dirname $0) && echo $PWD) +ctf_tests= +ctf_compiler="gcc" +ctf_convert="ctfconvert" +ctf_merge="ctfmerge" +ctf_debugflags="-gdwarf-2 " +ctf_mach32="-m32" +ctf_mach64="-m64" +ctf_32cflags="$ctf_mach32 $ctf_debugflags" +ctf_64cflags="$ctf_mach64 $ctf_debugflags" +ctf_temp="$TMPDIR/ctftest.$$.o" +ctf_makefile="Makefile.ctftest" +ctf_nerrs=0 + +usage() +{ + typeset msg="$*" + [[ -z "$msg" ]] || echo "$msg" >&2 + cat <<USAGE >&2 +Usage: $ctf_arg0 [-c compiler] [-g flags] [-m ctfmerge] [-t ctfconvert] + + Runs the CTF test suite + + -c compiler Use the specified compiler, defaults to 'gcc' + on path. + -g flags Use flags to generate debug info. Defaults to + "-gdwarf-2". + -m ctfmerge Use the specified ctfmerge, defaults to + 'ctfmerge' on path. + -t ctfconvert Use the specified ctfconvert, defaults to + 'ctfconvert' on path. +USAGE + exit 2 +} + + +test_fail() +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "TEST FAILED: $msg" >&2 + ((ctf_nerrs++)) +} + +fatal() +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "$ctf_arg0: $msg" >&2 + rm -f "$ctf_tmp32" "$ctf_temp64" + exit 1 +} + +check_env() +{ + if which "$1" 2>/dev/null >/dev/null; then + return + fi + + [[ -f "$1" ]] || fatal "failed to find tool $1" +} + +announce() +{ + cat << EOF +Beginning CTF tests with the following settings: +COMPILER: $(which $ctf_compiler) +CTFCONVERT: $(which $ctf_convert) +CTFMERGE: $(which $ctf_merge) +32-bit CFLAGS: $ctf_32cflags +64-bit CFLAGS: $ctf_64cflags + +EOF +} + +run_one() +{ + typeset source=$1 checker=$2 flags=$3 + + if ! "$ctf_compiler" $flags -o "$ctf_temp" -c "$source"; then + test_fail "failed to compile $source with flags: $flags" + return + fi + + if ! "$ctf_convert" "$ctf_temp"; then + test_fail "failed to convert CTF in $source" + return + fi + + if ! "$checker" "$ctf_temp"; then + test_fail "check for $source, $checker, failed" + return + fi + + echo "TEST PASSED: $source $flags" +} + +# +# Perform a more complex build. The Makefile present will drive the +# building of the artifacts and the running of the tests based on the +# variables that we pass to it. +# +run_dir() +{ + typeset dir outdir check32 check64 flags32 flags64 + + dir=$1 + outdir="$TMPDIR/ctftest.$$-$(basename $d)" + check32=$2 + flags32=$3 + check64=$4 + flags64=$5 + + if ! mkdir $outdir; then + fatal "failed to make temporary directory '$outdir'" + fi + + if ! make -C $dir -f Makefile.ctftest \ + BUILDDIR="$outdir" \ + CC="$ctf_compiler" \ + CFLAGS32="$ctf_mach32" \ + CFLAGS64="$ctf_mach64" \ + DEBUGFLAGS="$ctf_debugflags" \ + CTFCONVERT="$ctf_convert" \ + CTFMERGE="$ctf_merge" \ + build 1>/dev/null; then + rm -rf $outdir + test_fail "failed to build $dir" + return + fi + + if ! make -C $dir -f Makefile.ctftest \ + BUILDDIR="$outdir" \ + CHECK32="$check32" \ + CHECK64="$check64" \ + run-test 1>/dev/null; then + rm -rf $outdir + test_fail "failed to run tests for $dir" + return + fi + + rm -rf $outdir + echo "TEST PASSED: $dir (dir)" +} + +# +# Find all of the tests that exist and then try to run them all. Tests +# may either be a single file or a directory. +# +run_tests() +{ + typeset t base check + ctf_tests=$(ls "$ctf_root"/*.c) + for t in $ctf_tests; do + base=$(basename "$t" .c) + check=$(echo "$base" | sed s/test-/check-/) + if [[ -f "$ctf_root/$check" ]]; then + run_one $t "$ctf_root/$check" "$ctf_32cflags" + run_one $t "$ctf_root/$check" "$ctf_64cflags" + elif [[ -f "$ctf_root/$check-32" && \ + -f "$ctf_root/$check-64" ]]; then + run_one $t "$ctf_root/$check-32" "$ctf_32cflags" + run_one $t "$ctf_root/$check-64" "$ctf_64cflags" + else + test_fail "missing checker for $t" + fi + done + + for d in $(find "$ctf_root" -maxdepth 1 -type d -name 'test-*'); do + [[ ! -f "$d/$ctf_makefile" ]] && continue + base=$(basename "$d") + check=$(echo "$base" | sed s/test-/check-/) + if [[ -f "$ctf_root/$check" ]]; then + run_dir $d "$ctf_root/$check" "$ctf_32cflags" \ + "$ctf_root/$check" "$ctf_64cflags" + elif [[ -f "$ctf_root/$check-32" && \ + -f "$ctf_root/$check-64" ]]; then + run_dir $d "$ctf_root/$check-32" "$ctf_32cflags" \ + "$ctf_root/$check-64" "$ctf_64cflags" + else + test_fail "missing checker for $t" + fi + done +} + +while getopts ":c:g:m:t:" c $@; do + case "$c" in + c) + ctf_compiler=$OPTARG + ;; + g) + ctf_debugflags=$OPTARG + ;; + m) + ctf_merge=$OPTARG + ;; + t) + ctf_convert=$OPTARG + ;; + :) + usage "option requires an argument -- $OPTARG" + ;; + *) + usage "invalid option -- $OPTARG" + ;; + esac +done + +ctf_32cflags="$ctf_mach32 $ctf_debugflags" +ctf_64cflags="$ctf_mach64 $ctf_debugflags" + +check_env "$ctf_compiler" +check_env "$ctf_convert" +check_env "$ctf_merge" +announce + +run_tests + +if [[ $ctf_nerrs -ne 0 ]]; then + if [[ $ctf_nerrs -eq 1 ]]; then + printf "\n%s: %u test failed\n" "$ctf_arg0" "$ctf_nerrs" + else + printf "\n%s: %u tests failed\n" "$ctf_arg0" "$ctf_nerrs" + fi +else + printf "\n%s: All tests passed successfully\n" "$ctf_arg0" + exit 0 +fi diff --git a/usr/src/test/util-tests/tests/ctf/test-array.c b/usr/src/test/util-tests/tests/ctf/test-array.c new file mode 100644 index 0000000000..9c15771caf --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-array.c @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/* + * A series of basic array tests with simple base types. + */ + +int a[3]; +double b[42]; +const char *c[] = { "17" "31", "169" }; + +int d[4][5]; +int e[4][5][6]; +int f[4][5][6][7]; +int g[4][5][6][7][8]; +int h[4][5][6][7][8][9]; +int i[4][5][6][7][8][9][10]; diff --git a/usr/src/test/util-tests/tests/ctf/test-enum.c b/usr/src/test/util-tests/tests/ctf/test-enum.c new file mode 100644 index 0000000000..f6bfbfccb0 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-enum.c @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include <stdint.h> + +/* + * Basic sanity checking of enumerations, using specific numbers and arbitrary + * numbers. + */ + +enum ff6 { + TERRA, + LOCKE, + EDGAR, + SABIN, + CELES, + CYAN, + SHADOW, + GAU, + SETZER, + STRAGO, + RELM, + MOG, + GOGO, + UMARO, + LEO, + KEFKA +}; + +typedef enum ff10 { + TIDUS = -10, + YUNA = 23, + AURON = -34, + WAKA = 52, + LULU = INT32_MAX, + RIKKU = INT32_MIN, + KHIMARI = 0 +} ff10_t; + +/* + * The following enum is copy of the ddi_hp_cn_state_t enumeration which was + * previously incorrectly converted by the tools. Notably, we always assumed + * that the DWARF enum values were signed; however, in this case we needed to + * check for an unsigned version before a signed version, otherwise some of the + * entries below will have the wrong values. + */ +typedef enum chrono { + CRONO = 0x1000, + LUCCA = 0x2000, + MARLE = 0x3000, + FROG = 0x4000, + ROBO = 0x5000, + AYLA = 0x6000, + MAGUS = 0x7000, + SCHALA = 0x8000, + LAVOS = 0x9000, + BALTHAZAR = 0xa000 +} chrono_t; + +enum ff6 ff6; +ff10_t ff10; +chrono_t trigger; diff --git a/usr/src/test/util-tests/tests/ctf/test-float.c b/usr/src/test/util-tests/tests/ctf/test-float.c new file mode 100644 index 0000000000..ddec7a7167 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-float.c @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include <complex.h> + +/* + * Test floating point types. Unfortunately neither gcc nor clang support the + * imaginary keyword which means that we cannot test it. + */ + +float a; +double b; +long double c; +float complex d; +double complex e; +long double complex f; diff --git a/usr/src/test/util-tests/tests/ctf/test-forward.c b/usr/src/test/util-tests/tests/ctf/test-forward.c new file mode 100644 index 0000000000..4aa0fa2486 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-forward.c @@ -0,0 +1,34 @@ +/* + * 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 the use of forward declarations of unknown types. + */ + +struct foo; +union bar; +enum baz; + +struct forward { + struct foo *prev; + struct foo *next; + union bar *data; + enum baz *tag; +}; + +struct foo *foop; +union bar *barp; +enum baz *bazp; +struct forward forward; diff --git a/usr/src/test/util-tests/tests/ctf/test-function.c b/usr/src/test/util-tests/tests/ctf/test-function.c new file mode 100644 index 0000000000..af999b5c78 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-function.c @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <string.h> + +/* + * Test various function and function pointer cases. + */ + +static void +simple_func(void) +{ +} + +static void +one(int v) +{ +} + +static void +two(int v, const char *a) +{ +} + +static void +three(int v, const char *a, float b) +{ +} + +static const char * +noarg(void) +{ + return ("hello, world"); +} + +static const char * +argument(uintptr_t base) +{ + return ((const char *)(base + 1)); +} + +static void +vararg(const char *foo, ...) +{ + +} + +static uintptr_t +vararg_ret(const char *foo, ...) +{ + return ((uintptr_t)foo); +} + +typedef int (*strfunc_t)(const char *, const char *); +typedef void (*vararg_t)(const char *, ...); + +strfunc_t s = strcmp; +vararg_t v = vararg; diff --git a/usr/src/test/util-tests/tests/ctf/test-int.c b/usr/src/test/util-tests/tests/ctf/test-int.c new file mode 100644 index 0000000000..d7cca69956 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-int.c @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* + * Test basic integer types. Note that signed types are considered the same as + * the base type. + */ + +char a; +unsigned char b; + +short d; +unsigned short e; + +int g; +unsigned int h; + +long j; +unsigned long k; + +long long m; +unsigned long long n; diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest new file mode 100644 index 0000000000..e19e461a1a --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/Makefile.ctftest @@ -0,0 +1,39 @@ +# +# 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 2019 Joyent, Inc. +# + +TEST = test-merge-dedup + +OBJS_C_32 = $(BUILDDIR)/test-merge-1.32.c.o \ + $(BUILDDIR)/test-merge-2.32.c.o \ + $(BUILDDIR)/test-merge-3.32.c.o \ + $(BUILDDIR)/test-merge-dedup.32.c.o + +OBJS_C_64 = $(BUILDDIR)/test-merge-1.64.c.o \ + $(BUILDDIR)/test-merge-2.64.c.o \ + $(BUILDDIR)/test-merge-3.64.c.o \ + $(BUILDDIR)/test-merge-dedup.64.c.o + +OBJS_M_32 = $(BUILDDIR)/test-merge-1.32.m.o \ + $(BUILDDIR)/test-merge-2.32.m.o \ + $(BUILDDIR)/test-merge-3.32.m.o \ + $(BUILDDIR)/test-merge-dedup.32.m.o + +OBJS_M_64 = $(BUILDDIR)/test-merge-1.64.m.o \ + $(BUILDDIR)/test-merge-2.64.m.o \ + $(BUILDDIR)/test-merge-3.64.m.o \ + $(BUILDDIR)/test-merge-dedup.64.m.o + + +include ../Makefile.ctftest.com diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c new file mode 100644 index 0000000000..7119026d83 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-1.c @@ -0,0 +1,27 @@ +/* + * 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. + */ + +int f; +short g; +const char *h; +float i; +double j; + +struct dup { + int dup; + int dup2; +}; + +struct dup dup1; diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c new file mode 100644 index 0000000000..5d3da5b082 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-2.c @@ -0,0 +1,27 @@ +/* + * 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. + */ + +int k; +short l; +const char *m; +float n; +double o; + +struct dup { + int dup; + int dup2; +}; + +struct dup dup2; diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c new file mode 100644 index 0000000000..81ed216743 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-3.c @@ -0,0 +1,27 @@ +/* + * 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. + */ + +int p; +short q; +const char *r; +float s; +double t; + +struct dup { + int dup; + int dup2; +}; + +struct dup dup3; diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c new file mode 100644 index 0000000000..798457bd05 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-dedup/test-merge-dedup.c @@ -0,0 +1,33 @@ +/* + * 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. + */ + +int a; +short b; +const char *c; +float d; +double e; + +struct dup { + int dup; + int dup2; +}; + +struct dup dupmain; + +int +main(int argc, const char *argv[]) +{ + return (0); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest new file mode 100644 index 0000000000..270264370e --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/Makefile.ctftest @@ -0,0 +1,30 @@ +# +# 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.c.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +TEST = test-merge-forward + +OBJS_C_32 = $(BUILDDIR)/test-merge.32.c.o \ + $(BUILDDIR)/test-impl.32.c.o + +OBJS_C_64 = $(BUILDDIR)/test-merge.64.c.o \ + $(BUILDDIR)/test-impl.64.c.o + +OBJS_M_32 = $(BUILDDIR)/test-merge.32.m.o \ + $(BUILDDIR)/test-impl.32.m.o + +OBJS_M_64 = $(BUILDDIR)/test-merge.64.m.o \ + $(BUILDDIR)/test-impl.64.m.o + +include ../Makefile.ctftest.com diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c new file mode 100644 index 0000000000..c4319032a0 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-impl.c @@ -0,0 +1,29 @@ +/* + * 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. + */ + +struct foo { + struct foo *next; + int left; + int right; + int count; +}; + +void +mumble(struct foo *foo) +{ + foo->left = foo->right - foo->count; + foo->count += foo->right; + foo->right--; +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c new file mode 100644 index 0000000000..ab986d920b --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-forward/test-merge.c @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#include <stdio.h> + +struct foo; + +typedef struct foo_list { + int count; + struct foo *head; + struct foo *tail; +} foo_list_t; + +foo_list_t list; + +int +main(void) +{ + (void) printf("%p", &list); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest new file mode 100644 index 0000000000..3cf1fd647f --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/Makefile.ctftest @@ -0,0 +1,92 @@ +# +# 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 2019 Joyent, Inc. +# + +# +# This makefile could be simplified substantially. However, it does +# everything explicitly to try and work with a wide variety of different +# makes. +# +# The following values should be passed in by the invoker of the +# Makefile: +# +# CC C Compiler to use +# CFLAGS32 32-bit CFLAGS +# CFLAGS64 64-bit CFLAGS +# CTFCONVERT Path to ctfconvert +# CTFMERGE Path to ctfmerge +# DEBUGFLAGS The set of debug flags to use +# BUILDDIR Directory things should be built in +# CHECK32 Program to check 32-bit output +# CHECK64 Program to check 64-bit output +# + +OBJS_C_32 = $(BUILDDIR)/test-global.32.c.o \ + $(BUILDDIR)/test-scoped.32.c.o + +OBJS_C_64 = $(BUILDDIR)/test-global.64.c.o \ + $(BUILDDIR)/test-scoped.64.c.o + +OBJS_M_32 = $(BUILDDIR)/test-global.32.m.o \ + $(BUILDDIR)/test-scoped.32.m.o + +OBJS_M_64 = $(BUILDDIR)/test-global.64.m.o \ + $(BUILDDIR)/test-scoped.64.m.o + +BINS = $(BUILDDIR)/test-merge-reduction-32c.so.1 \ + $(BUILDDIR)/test-merge-reduction-32m.so.1 \ + $(BUILDDIR)/test-merge-reduction-64c.so.1 \ + $(BUILDDIR)/test-merge-reduction-64m.so.1 \ + +CFLAGS = -fPIC +LDFLAGS = -shared -Wl,-Mmapfile-vers -Wl,-ztext -Wl,-zdefs \ + -htest-merge-reduction.so.1 + +build: $(BINS) + +$(BUILDDIR)/%.32.c.o: %.c + $(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $< + +$(BUILDDIR)/%.64.c.o: %.c + $(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $< + +$(BUILDDIR)/%.32.m.o: %.c + $(CC) $(CFLAGS) $(CFLAGS32) $(DEBUGFLAGS) -o $@ -c $< + $(CTFCONVERT) $@ + +$(BUILDDIR)/%.64.m.o: %.c + $(CC) $(CFLAGS) $(CFLAGS64) $(DEBUGFLAGS) -o $@ -c $< + $(CTFCONVERT) $@ + +$(BUILDDIR)/test-merge-reduction-32c.so.1: $(OBJS_C_32) + $(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_32) + $(CTFCONVERT) $@ + +$(BUILDDIR)/test-merge-reduction-64c.so.1: $(OBJS_C_64) + $(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_C_64) + $(CTFCONVERT) $@ + +$(BUILDDIR)/test-merge-reduction-32m.so.1: $(OBJS_M_32) + $(CC) $(CFLAGS32) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_32) + $(CTFMERGE) -t -o $@ $(OBJS_M_32) + +$(BUILDDIR)/test-merge-reduction-64m.so.1: $(OBJS_M_64) + $(CC) $(CFLAGS64) $(CFLAGS) $(LDFLAGS) $(DEBUGFLAGS) -o $@ $(OBJS_M_64) + $(CTFMERGE) -t -o $@ $(OBJS_M_64) + +run-test: + $(CHECK32) $(BUILDDIR)/test-merge-reduction-32c.so.1 + $(CHECK64) $(BUILDDIR)/test-merge-reduction-64c.so.1 + $(CHECK32) $(BUILDDIR)/test-merge-reduction-32m.so.1 + $(CHECK64) $(BUILDDIR)/test-merge-reduction-64m.so.1 diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers new file mode 100644 index 0000000000..c1e47627ad --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/mapfile-vers @@ -0,0 +1,37 @@ +# +# 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 2019 Joyent, Inc. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +$mapfile_version 2 + +SYMBOL_VERSION CTFTEST { + global: + global; + local: + *; +}; diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c new file mode 100644 index 0000000000..09f2914c12 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-global.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + + +#include <stdlib.h> + +extern int scoped(uint32_t); + +int +global(void) +{ + return (scoped(arc4random())); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c new file mode 100644 index 0000000000..a30fe7a7b7 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-reduction/test-scoped.c @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <limits.h> + +int data; + +int +scoped(uint32_t a) +{ + if (a >= INT32_MAX) { + data = a - INT32_MAX; + } + + return (data); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest new file mode 100644 index 0000000000..7d5a875bce --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/Makefile.ctftest @@ -0,0 +1,42 @@ +# +# 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 2019 Joyent, Inc. +# + +TEST = test-merge-static + +OBJS_C_32 = $(BUILDDIR)/test-a.32.c.o \ + $(BUILDDIR)/test-b.32.c.o \ + $(BUILDDIR)/test-c.32.c.o \ + $(BUILDDIR)/test-d.32.c.o \ + $(BUILDDIR)/test-main.32.c.o + +OBJS_C_64 = $(BUILDDIR)/test-a.64.c.o \ + $(BUILDDIR)/test-b.64.c.o \ + $(BUILDDIR)/test-c.64.c.o \ + $(BUILDDIR)/test-d.64.c.o \ + $(BUILDDIR)/test-main.64.c.o + +OBJS_M_32 = $(BUILDDIR)/test-a.32.m.o \ + $(BUILDDIR)/test-b.32.m.o \ + $(BUILDDIR)/test-c.32.m.o \ + $(BUILDDIR)/test-d.32.m.o \ + $(BUILDDIR)/test-main.32.m.o + +OBJS_M_64 = $(BUILDDIR)/test-a.64.m.o \ + $(BUILDDIR)/test-b.64.m.o \ + $(BUILDDIR)/test-c.64.m.o \ + $(BUILDDIR)/test-d.64.m.o \ + $(BUILDDIR)/test-main.64.m.o + +include ../Makefile.ctftest.com diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c new file mode 100644 index 0000000000..749e9fbd22 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-a.c @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include <sys/types.h> + +static uint8_t global; + +static uint8_t +mumble(uint8_t a) +{ + return (a); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c new file mode 100644 index 0000000000..7fca620966 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-b.c @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include <sys/types.h> + +static uint16_t global; + +static uint16_t +mumble(uint16_t a) +{ + return (a); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c new file mode 100644 index 0000000000..2627cec22c --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-c.c @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include <sys/types.h> + +static uint32_t global; + +static uint32_t +mumble(uint32_t a) +{ + return (a); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c new file mode 100644 index 0000000000..516b6c2fa2 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-d.c @@ -0,0 +1,24 @@ +/* + * 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. + */ + +#include <sys/types.h> + +static uint64_t global; + +static uint64_t +mumble(uint64_t a) +{ + return (a); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c new file mode 100644 index 0000000000..e645302f8b --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-static/test-main.c @@ -0,0 +1,28 @@ +/* + * 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. + */ + +int global; + +int +mumble(int a) +{ + return (a); +} + +int +main(void) +{ + return (0); +} diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest new file mode 100644 index 0000000000..35b3ecf69c --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/Makefile.ctftest @@ -0,0 +1,23 @@ +# +# 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.c.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +TEST = test-merge-weak + +OBJS_C_32 = $(BUILDDIR)/test-merge-weak.32.c.o +OBJS_C_64 = $(BUILDDIR)/test-merge-weak.64.c.o +OBJS_M_32 = $(BUILDDIR)/test-merge-weak.32.m.o +OBJS_M_64 = $(BUILDDIR)/test-merge-weak.64.m.o + +include ../Makefile.ctftest.com diff --git a/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c new file mode 100644 index 0000000000..7d47c02fea --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-merge-weak/test-merge-weak.c @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include <stdlib.h> + +#pragma weak mumble = _mumble +#pragma weak foo = _foo + +int _foo = 5; + +int +_mumble(void) +{ + return ((int)arc4random()); +} + +int +main(void) +{ + return (mumble()); +}; diff --git a/usr/src/test/util-tests/tests/ctf/test-reference.c b/usr/src/test/util-tests/tests/ctf/test-reference.c new file mode 100644 index 0000000000..b738a2e429 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-reference.c @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/* + * Test the encoding of references to another type. Specifically the references + * that we generally care about are things like: + * + * o pointers + * o typedefs + * o const + * o volatile + * o restrict + */ + +int a; +typedef int test_int_t; +test_int_t aa; +const short b; +volatile float c; + +int *d; +int **dd; +int ***ddd; +test_int_t *e; +const test_int_t *ce; +volatile test_int_t *ve; +volatile const test_int_t *cve; +int *const *f; +const char *const g; + +typedef int *const * foo_t; +const volatile foo_t *cvh; diff --git a/usr/src/test/util-tests/tests/ctf/test-sou.c b/usr/src/test/util-tests/tests/ctf/test-sou.c new file mode 100644 index 0000000000..8194248df5 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-sou.c @@ -0,0 +1,246 @@ +/* + * 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. + */ + +#include <sys/types.h> +#include <complex.h> + +/* + * Test various structure and union constructs, including various things that + * have caused regressions in the past. + */ + +/* + * Basic, simple struct. + */ +struct foo { + int a; + float b; + const char *c; +}; + +struct foo foo; + +/* + * Self-referential structs + */ +struct node { + struct node *prev; + struct node *next; +}; + +typedef struct nlist { + size_t size; + size_t off; + struct node head; +} nlist_t; + +nlist_t head; + +/* + * Struct that has a forward declaration. + */ +typedef struct forward forward_t; +struct forward { + void *past; + void *present; + void *future; +}; + +const forward_t forward; + +/* + * Here, we have a pair of structures that basically round up to different + * sizes. As in, the size of the structure is somewhat compiler dependent. + */ +struct round_up { + uint8_t triforce; + uint32_t link; + uint8_t zelda; + uint8_t ganon; +}; + +#pragma pack(1) +struct fixed_up { + uint8_t triforce; + uint32_t link; + uint8_t zelda; + uint8_t ganon; +}; +#pragma pack() + +struct round_up oot; +struct fixed_up botw; + +/* + * Various GNU and c99 style arrays + */ +enum material { + COPPER, + IRON, + STEEL, + ADAMANTIUM, + MYTHRIL, + ORIHALCUM +}; + +struct component { + enum material m; + uint64_t grade; + uint64_t count; + const char *locations[4]; +}; + +struct mysterious_barrel { + const char *name; + size_t capacity; + struct component optional[]; +}; + +struct dusk_barrel { + const char *name; + size_t opacity; + struct component optional[0]; +}; + +struct mysterious_barrel sophie; +struct dusk_barrel ayesha; + +/* + * Various bitfield forms. + */ + +/* + * Variant of the Intel system_desc. + */ +struct stats { + uint64_t hp:16; + uint64_t mp:16; + uint64_t str:8; + uint64_t dex:4; + uint64_t con:1; + uint64_t inte:2; + uint64_t wis:1; + uint64_t cha:4; + uint64_t sanity:1; + uint64_t attack:2; + uint64_t mattack:1; + uint64_t defense:8; + uint64_t mdefense:32; + uint64_t evasion:8; + uint64_t crit:5; + uint64_t luck:19; +}; + +struct stats stats; + +/* + * More odd length structures due to bitfields + */ +struct fellowship { + uint16_t frodo:1; + uint16_t sam:1; + uint16_t merry:1; + uint16_t pippin:1; + uint16_t aragorn:1; + uint16_t boromir:1; + uint16_t legolas:1; + uint16_t gimli:1; + uint16_t gandalf:1; +}; + +struct fellowship ring; + +struct rings { + uint32_t elves:3; + uint32_t dwarves:7; + uint32_t men:9; + uint8_t one; + uint8_t silmarils[3]; +}; + +struct rings rings; + +/* + * Regression, we didn't handle receiving a negative offset from DWARF with + * this. + */ +#pragma pack(1) +struct csts { + unsigned int rdy:7; + unsigned int csts:32; +}; + +struct csts nvme; +#pragma pack() + +/* + * Onto unions + */ +union jrpg { + int ff; + double atelier[4]; + const char *tales; + int (*chrono)(void); + struct rings xeno; +}; + +union jrpg games; + +#pragma pack(1) +struct android { + uint32_t _2b:16; + uint32_t _9s:16; +}; + +union nier { + uint32_t automata; + struct android android; +}; +#pragma pack() + +union nier nier; + +union kh { + int sora:3; + char riku:7; + double kairi; + complex double namine; +}; + +union kh kh; + +/* + * Anonymous union in a struct, GNU extension / C11 + */ + +struct trigger { + uint8_t chrono; + uint8_t cross; + union { + void *lavos; + int *crono; + uint64_t schala[3]; + }; +}; + +struct trigger ct; + +/* + * This is an array/union combo that failed conversion previously. + */ +static const union regress { + unsigned int i[3]; + long double e; +} regress[9]; diff --git a/usr/src/test/util-tests/tests/ctf/test-weak.c b/usr/src/test/util-tests/tests/ctf/test-weak.c new file mode 100644 index 0000000000..d07981f369 --- /dev/null +++ b/usr/src/test/util-tests/tests/ctf/test-weak.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#pragma weak _strong = strong +#pragma weak _mumble = mumble + +int strong = 3; + +int +mumble(void) +{ + return (42); +} |