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