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