1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Check that we properly understand reference types and can walk through them
  18  * as well as generate them.
  19  */
  20 
  21 #include "check-common.h"
  22 
  23 static check_number_t check_base[] = {
  24         { "char", CTF_K_INTEGER, CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 },
  25         { "int", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 32 },
  26         { "float", CTF_K_FLOAT, CTF_FP_SINGLE, 0, 32 },
  27         { NULL }
  28 };
  29 
  30 static check_symbol_t check_syms[] = {
  31         { "a", "int" },
  32         { "aa", "test_int_t" },
  33         { "b", "const short" },
  34         { "c", "volatile float" },
  35         { "d", "int *" },
  36         { "dd", "int **" },
  37         { "ddd", "int ***" },
  38         { "e", "test_int_t *" },
  39         { "ce", "const test_int_t *" },
  40         { "ve", "volatile test_int_t *" },
  41         { "cve", "const volatile test_int_t *" },
  42         { "f", "int *const *" },
  43         { "g", "const char *const" },
  44         { NULL },
  45 };
  46 
  47 static check_descent_t check_descent_aa[] = {
  48         { "test_int_t", CTF_K_TYPEDEF },
  49         { "int", CTF_K_INTEGER },
  50         { NULL }
  51 };
  52 
  53 static check_descent_t check_descent_b[] = {
  54         { "const short", CTF_K_CONST },
  55         { "short", CTF_K_INTEGER },
  56         { NULL }
  57 };
  58 
  59 static check_descent_t check_descent_c[] = {
  60         { "volatile float", CTF_K_VOLATILE },
  61         { "float", CTF_K_FLOAT },
  62         { NULL }
  63 };
  64 
  65 static check_descent_t check_descent_d[] = {
  66         { "int *", CTF_K_POINTER },
  67         { "int", CTF_K_INTEGER },
  68         { NULL }
  69 };
  70 
  71 static check_descent_t check_descent_dd[] = {
  72         { "int **", CTF_K_POINTER },
  73         { "int *", CTF_K_POINTER },
  74         { "int", CTF_K_INTEGER },
  75         { NULL }
  76 };
  77 
  78 static check_descent_t check_descent_ddd[] = {
  79         { "int ***", CTF_K_POINTER },
  80         { "int **", CTF_K_POINTER },
  81         { "int *", CTF_K_POINTER },
  82         { "int", CTF_K_INTEGER },
  83         { NULL }
  84 };
  85 
  86 static check_descent_t check_descent_e[] = {
  87         { "test_int_t *", CTF_K_POINTER },
  88         { "test_int_t", CTF_K_TYPEDEF },
  89         { "int", CTF_K_INTEGER },
  90         { NULL },
  91 };
  92 
  93 static check_descent_t check_descent_ce[] = {
  94         { "const test_int_t *", CTF_K_POINTER },
  95         { "const test_int_t", CTF_K_CONST },
  96         { "test_int_t", CTF_K_TYPEDEF },
  97         { "int", CTF_K_INTEGER },
  98         { NULL },
  99 };
 100 
 101 static check_descent_t check_descent_ve[] = {
 102         { "volatile test_int_t *", CTF_K_POINTER},
 103         { "volatile test_int_t", CTF_K_VOLATILE },
 104         { "test_int_t", CTF_K_TYPEDEF },
 105         { "int", CTF_K_INTEGER },
 106         { NULL }
 107 };
 108 
 109 static check_descent_t check_descent_cve[] = {
 110         { "const volatile test_int_t *", CTF_K_POINTER },
 111         { "const volatile test_int_t", CTF_K_CONST },
 112         { "volatile test_int_t", CTF_K_VOLATILE },
 113         { "test_int_t", CTF_K_TYPEDEF },
 114         { "int", CTF_K_INTEGER },
 115         { NULL }
 116 };
 117 
 118 static check_descent_t check_descent_f[] = {
 119         { "int *const *", CTF_K_POINTER },
 120         { "int *const", CTF_K_CONST },
 121         { "int *", CTF_K_POINTER },
 122         { "int", CTF_K_INTEGER },
 123         { NULL }
 124 };
 125 
 126 static check_descent_t check_descent_g[] = {
 127         { "const char *const", CTF_K_CONST },
 128         { "const char *", CTF_K_POINTER },
 129         { "const char", CTF_K_CONST },
 130         { "char", CTF_K_INTEGER },
 131         { NULL }
 132 };
 133 
 134 static check_descent_test_t descents[] = {
 135         { "aa", check_descent_aa },
 136         { "b", check_descent_b },
 137         { "c", check_descent_c },
 138         { "d", check_descent_d },
 139         { "dd", check_descent_dd },
 140         { "ddd", check_descent_ddd },
 141         { "e", check_descent_e },
 142         { "ce", check_descent_ce },
 143         { "ve", check_descent_ve },
 144         { "cve", check_descent_cve },
 145         { "f", check_descent_f },
 146         { "g", check_descent_g },
 147         { NULL }
 148 };
 149 
 150 static check_descent_t check_descent_cvh_gcc4[] = {
 151         { "const volatile foo_t *", CTF_K_POINTER },
 152         { "const volatile foo_t", CTF_K_CONST },
 153         { "volatile foo_t", CTF_K_VOLATILE },
 154         { "foo_t", CTF_K_TYPEDEF },
 155         { "int *const *", CTF_K_POINTER },
 156         { "int *const", CTF_K_CONST },
 157         { "int *", CTF_K_POINTER },
 158         { "int", CTF_K_INTEGER },
 159         { NULL }
 160 };
 161 
 162 static check_descent_t check_descent_cvh_gcc7[] = {
 163         { "volatile const foo_t *", CTF_K_POINTER },
 164         { "volatile const foo_t", CTF_K_VOLATILE },
 165         { "const foo_t", CTF_K_CONST },
 166         { "foo_t", CTF_K_TYPEDEF },
 167         { "int *const *", CTF_K_POINTER },
 168         { "int *const", CTF_K_CONST },
 169         { "int *", CTF_K_POINTER },
 170         { "int", CTF_K_INTEGER },
 171         { NULL }
 172 };
 173 
 174 /*
 175  * GCC versions differ in how they order qualifiers, which is a shame for
 176  * round-tripping; but as they're clearly both valid, we should cope.  We'll
 177  * just insist that at least one of these checks passes.
 178  */
 179 static check_descent_test_t alt_descents[] = {
 180         { "cvh", check_descent_cvh_gcc4 },
 181         { "cvh", check_descent_cvh_gcc7 },
 182 };
 183 
 184 int
 185 main(int argc, char *argv[])
 186 {
 187         int i, ret = 0;
 188 
 189         if (argc < 2) {
 190                 errx(EXIT_FAILURE, "missing test files");
 191         }
 192 
 193         for (i = 1; i < argc; i++) {
 194                 ctf_file_t *fp;
 195                 int alt_ok = 0;
 196                 uint_t d;
 197 
 198                 if ((fp = ctf_open(argv[i], &ret)) == NULL) {
 199                         warnx("failed to open %s: %s", argv[i],
 200                             ctf_errmsg(ret));
 201                         ret = EXIT_FAILURE;
 202                         continue;
 203                 }
 204 
 205                 if (!ctftest_check_numbers(fp, check_base))
 206                         ret = EXIT_FAILURE;
 207                 if (!ctftest_check_symbols(fp, check_syms))
 208                         ret = EXIT_FAILURE;
 209                 for (d = 0; descents[d].cdt_sym != NULL; d++) {
 210                         if (!ctftest_check_descent(descents[d].cdt_sym, fp,
 211                             descents[d].cdt_tests, B_FALSE)) {
 212                                 ret = EXIT_FAILURE;
 213                         }
 214                 }
 215 
 216                 for (d = 0; alt_descents[d].cdt_sym != NULL; d++) {
 217                         if (ctftest_check_descent(alt_descents[d].cdt_sym, fp,
 218                             alt_descents[d].cdt_tests, B_TRUE)) {
 219                                 alt_ok = 1;
 220                                 break;
 221                         }
 222                 }
 223 
 224                 if (!alt_ok) {
 225                         warnx("all descents failed for %s",
 226                             alt_descents[0].cdt_sym);
 227                         ret = EXIT_FAILURE;
 228                 }
 229 
 230                 ctf_close(fp);
 231         }
 232 
 233         return (ret);
 234 }