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