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 handle structures and unions.
18  */
19 
20 #include "check-common.h"
21 
22 static check_number_t check_bitfields[] = {
23 #ifdef	TARGET_LP64
24 	{ "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 },
25 	{ "unsigned long:2", CTF_K_INTEGER,  0, 0, 2 },
26 	{ "unsigned long:4", CTF_K_INTEGER,  0, 0, 4 },
27 	{ "unsigned long:5", CTF_K_INTEGER,  0, 0, 5 },
28 	{ "unsigned long:8", CTF_K_INTEGER,  0, 0, 8 },
29 	{ "unsigned long:16", CTF_K_INTEGER,  0, 0, 16 },
30 	{ "unsigned long:19", CTF_K_INTEGER,  0, 0, 19 },
31 	{ "unsigned long:32", CTF_K_INTEGER,  0, 0, 32 },
32 #else
33 	{ "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 },
34 	{ "unsigned long long:2", CTF_K_INTEGER,  0, 0, 2 },
35 	{ "unsigned long long:4", CTF_K_INTEGER,  0, 0, 4 },
36 	{ "unsigned long long:5", CTF_K_INTEGER,  0, 0, 5 },
37 	{ "unsigned long long:8", CTF_K_INTEGER,  0, 0, 8 },
38 	{ "unsigned long long:16", CTF_K_INTEGER,  0, 0, 16 },
39 	{ "unsigned long long:19", CTF_K_INTEGER,  0, 0, 19 },
40 	{ "unsigned long long:32", CTF_K_INTEGER,  0, 0, 32 },
41 #endif
42 	{ "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 },
43 	{ "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 },
44 	/*
45 	 * Skipped on clang as it doesn't process csts correctly. See
46 	 * check_members_csts.
47 	 */
48 	{ "unsigned int:32", CTF_K_INTEGER, 0, 0, 32, SKIP_CLANG },
49 	{ "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 },
50 	{ NULL }
51 };
52 
53 static check_symbol_t check_syms[] = {
54 	{ "foo", "struct foo" },
55 	{ "head", "nlist_t" },
56 	{ "forward", "const forward_t" },
57 	{ "oot", "struct round_up" },
58 	{ "botw", "struct fixed_up" },
59 	{ "sophie", "struct mysterious_barrel" },
60 	{ "ayesha", "struct dusk_barrel" },
61 	{ "stats", "struct stats" },
62 	{ "ring", "struct fellowship" },
63 	{ "rings", "struct rings" },
64 	{ "nvme", "struct csts" },
65 	{ "games", "union jrpg" },
66 	{ "nier", "union nier" },
67 	{ "kh", "union kh" },
68 	{ "ct", "struct trigger" },
69 	{ "regress", "const union regress [9]" },
70 	{ NULL }
71 };
72 
73 static check_member_t check_member_foo[] = {
74 	{ "a", "int", 0 },
75 	{ "b", "float", 4 * NBBY },
76 	{ "c", "const char *", 8 * NBBY },
77 	{ NULL }
78 };
79 
80 static check_member_t check_member_node[] = {
81 	{ "prev", "struct node *", 0 },
82 #ifdef	TARGET_LP64
83 	{ "next", "struct node *", 8 * NBBY },
84 #else
85 	{ "next", "struct node *", 4 * NBBY },
86 #endif
87 	{ NULL }
88 };
89 
90 static check_member_t check_member_nlist[] = {
91 	{ "size", "size_t", 0 },
92 #ifdef	TARGET_LP64
93 	{ "off", "size_t", 8 * NBBY },
94 	{ "head", "struct node", 16 * NBBY },
95 #else
96 	{ "off", "size_t", 4 * NBBY },
97 	{ "head", "struct node", 8 * NBBY },
98 #endif
99 	{ NULL }
100 };
101 
102 static check_member_t check_member_forward[] = {
103 	{ "past", "void *", 0 },
104 #ifdef	TARGET_LP64
105 	{ "present", "void *", 8 * NBBY },
106 	{ "future", "void *", 16 * NBBY },
107 #else
108 	{ "present", "void *", 4 * NBBY },
109 	{ "future", "void *", 8 * NBBY },
110 #endif
111 	{ NULL }
112 };
113 
114 static check_member_t check_member_round_up[] = {
115 	{ "triforce", "uint8_t", 0 },
116 	{ "link", "uint32_t", 4 * NBBY },
117 	{ "zelda", "uint8_t", 8 * NBBY },
118 	{ "ganon", "uint8_t", 9 * NBBY },
119 	{ NULL }
120 };
121 
122 static check_member_t check_member_fixed_up[] = {
123 	{ "triforce", "uint8_t", 0 },
124 	{ "link", "uint32_t", 1 * NBBY },
125 	{ "zelda", "uint8_t", 5 * NBBY },
126 	{ "ganon", "uint8_t", 6 * NBBY },
127 	{ NULL }
128 };
129 
130 #ifdef	TARGET_LP64
131 static check_member_t check_member_component[] = {
132 	{ "m", "enum material", 0 },
133 	{ "grade", "uint64_t", 8 * NBBY },
134 	{ "count", "uint64_t", 16 * NBBY },
135 	{ "locations", "const char *[4]", 24 * NBBY },
136 	{ NULL }
137 };
138 
139 static check_member_t check_member_mysterious[] = {
140 	{ "name", "const char *", 0 },
141 	{ "capacity", "size_t", 8 * NBBY },
142 	{ "optional", "struct component [0]", 16 * NBBY },
143 	{ NULL }
144 };
145 
146 static check_member_t check_member_dusk[] = {
147 	{ "name", "const char *", 0 },
148 	{ "opacity", "size_t", 8 * NBBY },
149 	{ "optional", "struct component [0]", 16 * NBBY },
150 	{ NULL }
151 };
152 
153 
154 static check_member_t check_member_stats[] = {
155 	{ "hp", "unsigned long:16", 0 },
156 	{ "mp", "unsigned long:16", 16 },
157 	{ "str", "unsigned long:8", 32 },
158 	{ "dex", "unsigned long:4", 40 },
159 	{ "con", "unsigned long:1", 44 },
160 	{ "inte", "unsigned long:2", 45 },
161 	{ "wis", "unsigned long:1", 47 },
162 	{ "cha", "unsigned long:4", 48 },
163 	{ "sanity", "unsigned long:1", 52 },
164 	{ "attack", "unsigned long:2", 53 },
165 	{ "mattack", "unsigned long:1", 55 },
166 	{ "defense", "unsigned long:8", 56 },
167 	{ "mdefense", "unsigned long:32", 64 },
168 	{ "evasion", "unsigned long:8", 96 },
169 	{ "crit", "unsigned long:5", 104 },
170 	{ "luck", "unsigned long:19", 109 },
171 	{ NULL }
172 };
173 #else
174 static check_member_t check_member_component[] = {
175 	{ "m", "enum material", 0 },
176 	{ "grade", "uint64_t", 4 * NBBY },
177 	{ "count", "uint64_t", 12 * NBBY },
178 	{ "locations", "const char *[4]", 20 * NBBY },
179 	{ NULL }
180 };
181 
182 static check_member_t check_member_mysterious[] = {
183 	{ "name", "const char *", 0 },
184 	{ "capacity", "size_t", 4 * NBBY },
185 	{ "optional", "struct component [0]", 8 * NBBY },
186 	{ NULL }
187 };
188 
189 static check_member_t check_member_dusk[] = {
190 	{ "name", "const char *", 0 },
191 	{ "opacity", "size_t", 4 * NBBY },
192 	{ "optional", "struct component [0]", 8 * NBBY },
193 	{ NULL }
194 };
195 
196 
197 static check_member_t check_member_stats[] = {
198 	{ "hp", "unsigned long long:16", 0 },
199 	{ "mp", "unsigned long long:16", 16 },
200 	{ "str", "unsigned long long:8", 32 },
201 	{ "dex", "unsigned long long:4", 40 },
202 	{ "con", "unsigned long long:1", 44 },
203 	{ "inte", "unsigned long long:2", 45 },
204 	{ "wis", "unsigned long long:1", 47 },
205 	{ "cha", "unsigned long long:4", 48 },
206 	{ "sanity", "unsigned long long:1", 52 },
207 	{ "attack", "unsigned long long:2", 53 },
208 	{ "mattack", "unsigned long long:1", 55 },
209 	{ "defense", "unsigned long long:8", 56 },
210 	{ "mdefense", "unsigned long long:32", 64 },
211 	{ "evasion", "unsigned long long:8", 96 },
212 	{ "crit", "unsigned long long:5", 104 },
213 	{ "luck", "unsigned long long:19", 109 },
214 	{ NULL }
215 };
216 #endif
217 
218 static check_member_t check_member_fellowship[] = {
219 	{ "frodo", "unsigned short:1", 0 },
220 	{ "sam", "unsigned short:1", 1 },
221 	{ "merry", "unsigned short:1", 2 },
222 	{ "pippin", "unsigned short:1", 3 },
223 	{ "aragorn", "unsigned short:1", 4 },
224 	{ "boromir", "unsigned short:1", 5 },
225 	{ "legolas", "unsigned short:1", 6 },
226 	{ "gimli", "unsigned short:1", 7 },
227 	{ "gandalf", "unsigned short:1", 8 },
228 	{ NULL }
229 };
230 
231 static check_member_t check_member_rings[] = {
232 	{ "elves", "unsigned int:3", 0 },
233 	{ "dwarves", "unsigned int:7", 3 },
234 	{ "men", "unsigned int:9", 10 },
235 	{ "one", "uint8_t", 3 * NBBY },
236 	{ "silmarils", "uint8_t [3]", 4 * NBBY },
237 	{ NULL }
238 };
239 
240 /*
241  * Unfortunately this test case fails with clang in at least versions 8-10. See
242  * https://bugs.llvm.org/show_bug.cgi?id=44601 for more information on the bug.
243  */
244 static check_member_t check_member_csts[] = {
245 	{ "rdy", "unsigned int:7", 0 },
246 	{ "csts", "unsigned int:32", 7 },
247 	{ NULL }
248 };
249 
250 static check_member_t check_member_jrpg[] = {
251 	{ "ff", "int", 0 },
252 	{ "atelier", "double [4]", 0 },
253 	{ "tales", "const char *", 0 },
254 	{ "chrono", "int (*)()", 0 },
255 	{ "xeno", "struct rings", 0 },
256 	{ NULL }
257 };
258 
259 static check_member_t check_member_android[] = {
260 	{ "_2b", "unsigned int:16", 0 },
261 	{ "_9s", "unsigned int:16", 16 },
262 	{ NULL }
263 };
264 
265 static check_member_t check_member_nier[] = {
266 	{ "automata", "uint32_t", 0 },
267 	{ "android", "struct android", 0 },
268 	{ NULL }
269 };
270 
271 static check_member_t check_member_kh[] = {
272 	{ "sora", "int:3", 0 },
273 	{ "riku", "char:7", 0 },
274 	{ "kairi", "double", 0 },
275 	{ "namine", "complex double", 0 },
276 	{ NULL }
277 };
278 
279 static check_member_t check_member_trigger[] = {
280 	{ "chrono", "uint8_t", 0 },
281 	{ "cross", "uint8_t", 8 },
282 	/*
283 	 * This test has an anonymous union. Unfortunately, there's not a great
284 	 * way to distinguish between various anonymous unions in this form.
285 	 */
286 #ifdef	TARGET_LP64
287 	{ "", "union ", 64 },
288 #else
289 	{ "", "union ", 32 },
290 #endif
291 	{ NULL }
292 };
293 
294 static check_member_t check_member_regress[] = {
295 	{ "i", "unsigned int [3]", 0 },
296 	{ "e", "long double", 0 },
297 	{ NULL }
298 };
299 
300 static check_member_test_t members[] = {
301 #ifdef	TARGET_LP64
302 	{ "struct foo", CTF_K_STRUCT, 16, check_member_foo },
303 	{ "struct node", CTF_K_STRUCT, 16, check_member_node },
304 	{ "struct nlist", CTF_K_STRUCT, 32, check_member_nlist },
305 	{ "struct forward", CTF_K_STRUCT, 24, check_member_forward },
306 #else
307 	{ "struct foo", CTF_K_STRUCT, 12, check_member_foo },
308 	{ "struct node", CTF_K_STRUCT, 8, check_member_node },
309 	{ "struct nlist", CTF_K_STRUCT, 16, check_member_nlist },
310 	{ "struct forward", CTF_K_STRUCT, 12, check_member_forward },
311 #endif
312 	{ "struct round_up", CTF_K_STRUCT, 12, check_member_round_up },
313 	{ "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up },
314 #ifdef	TARGET_LP64
315 	{ "struct component", CTF_K_STRUCT, 56, check_member_component },
316 	{ "struct mysterious_barrel", CTF_K_STRUCT, 16,
317 	    check_member_mysterious },
318 	{ "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk },
319 #else
320 	{ "struct component", CTF_K_STRUCT, 36, check_member_component },
321 	{ "struct mysterious_barrel", CTF_K_STRUCT, 8,
322 	    check_member_mysterious },
323 	{ "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk },
324 #endif
325 	{ "struct stats", CTF_K_STRUCT, 16, check_member_stats },
326 	{ "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship },
327 	{ "struct rings", CTF_K_STRUCT, 8, check_member_rings },
328 	{ "struct csts", CTF_K_STRUCT, 5, check_member_csts, SKIP_CLANG },
329 	{ "union jrpg", CTF_K_UNION, 32, check_member_jrpg },
330 	{ "struct android", CTF_K_STRUCT, 4, check_member_android },
331 	{ "union nier", CTF_K_UNION, 4, check_member_nier },
332 	{ "union kh", CTF_K_UNION, 16, check_member_kh },
333 #ifdef	TARGET_LP64
334 	{ "struct trigger", CTF_K_STRUCT, 32, check_member_trigger },
335 	{ "union regress", CTF_K_UNION, 16, check_member_regress },
336 #else
337 	{ "struct trigger", CTF_K_STRUCT, 28, check_member_trigger },
338 	{ "union regress", CTF_K_UNION, 12, check_member_regress },
339 #endif
340 	{ NULL }
341 };
342 
343 static check_descent_t check_descent_head[] = {
344 	{ "nlist_t", CTF_K_TYPEDEF },
345 	{ "struct nlist", CTF_K_STRUCT },
346 	{ NULL }
347 };
348 
349 static check_descent_t check_descent_forward[] = {
350 	{ "const forward_t", CTF_K_CONST },
351 	{ "forward_t", CTF_K_TYPEDEF },
352 	{ "struct forward", CTF_K_STRUCT },
353 	{ NULL }
354 };
355 
356 static check_descent_test_t descents[] = {
357 	{ "head", check_descent_head },
358 	{ "forward", check_descent_forward },
359 	{ NULL }
360 };
361 
362 static check_descent_t check_descent_regress_gcc4[] = {
363 	{ "const union regress [9]", CTF_K_CONST },
364 	{ "union regress [9]", CTF_K_ARRAY, "union regress", 9 },
365 	{ "union regress", CTF_K_UNION },
366 	{ NULL }
367 };
368 
369 static check_descent_t check_descent_regress_gcc7[] = {
370 	{ "const union regress [9]", CTF_K_ARRAY, "const union regress", 9 },
371 	{ "const union regress", CTF_K_CONST },
372 	{ "union regress", CTF_K_UNION },
373 	{ NULL }
374 };
375 
376 /*
377  * See needed_array_qualifier(): applying this fix means the qualifier order is
378  * different between GCC versions. Accept either form.
379  */
380 static check_descent_test_t alt_descents[] = {
381 	{ "regress", check_descent_regress_gcc4 },
382 	{ "regress", check_descent_regress_gcc7 },
383 	{ NULL }
384 };
385 
386 int
main(int argc,char * argv[])387 main(int argc, char *argv[])
388 {
389 	int i, ret = 0;
390 
391 	if (argc < 2) {
392 		errx(EXIT_FAILURE, "missing test files");
393 	}
394 
395 	for (i = 1; i < argc; i++) {
396 		ctf_file_t *fp;
397 		int alt_ok = 0;
398 		uint_t j;
399 
400 		if ((fp = ctf_open(argv[i], &ret)) == NULL) {
401 			warnx("failed to open %s: %s", argv[i],
402 			    ctf_errmsg(ret));
403 			ret = EXIT_FAILURE;
404 			continue;
405 		}
406 
407 		if (!ctftest_check_numbers(fp, check_bitfields))
408 			ret = EXIT_FAILURE;
409 		if (!ctftest_check_symbols(fp, check_syms))
410 			ret = EXIT_FAILURE;
411 		for (j = 0; descents[j].cdt_sym != NULL; j++) {
412 			if (!ctftest_check_descent(descents[j].cdt_sym, fp,
413 			    descents[j].cdt_tests, B_FALSE)) {
414 				ret = EXIT_FAILURE;
415 			}
416 		}
417 
418 		for (j = 0; alt_descents[j].cdt_sym != NULL; j++) {
419 			if (ctftest_check_descent(alt_descents[j].cdt_sym, fp,
420 			    alt_descents[j].cdt_tests, B_TRUE)) {
421 				alt_ok = 1;
422 				break;
423 			}
424 		}
425 
426 		if (!alt_ok) {
427 			warnx("all descents failed for %s",
428 			    alt_descents[0].cdt_sym);
429 			ret = EXIT_FAILURE;
430 		}
431 
432 		for (j = 0; members[j].cmt_type != NULL; j++) {
433 			if (ctftest_skip(members[j].cmt_skips)) {
434 				warnx("skipping members test %s due to "
435 				    "known compiler issue",
436 				    members[j].cmt_type);
437 				continue;
438 			}
439 
440 			if (!ctftest_check_members(members[j].cmt_type, fp,
441 			    members[j].cmt_kind, members[j].cmt_size,
442 			    members[j].cmt_members)) {
443 				ret = EXIT_FAILURE;
444 			}
445 		}
446 
447 		ctf_close(fp);
448 	}
449 
450 	return (ret);
451 }
452