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 2020 Joyent, Inc.
14 */
15
16 /*
17 * Collection of common utilities for CTF testing.
18 */
19
20 #include <strings.h>
21 #include <libctf.h>
22 #include "check-common.h"
23
24 typedef struct ctftests_lookup_cb {
25 ctf_file_t *clc_fp;
26 ctf_id_t clc_id;
27 const char *clc_name;
28 } ctftests_lookup_cb_t;
29
30 typedef struct ctftest_member_cb {
31 ctf_file_t *cmc_fp;
32 const check_member_t *cmc_members;
33 const char *cmc_name;
34 } ctftest_member_cb_t;
35
36 static int
ctftest_lookup_type_cb(ctf_id_t id,boolean_t root,void * arg)37 ctftest_lookup_type_cb(ctf_id_t id, boolean_t root, void *arg)
38 {
39 char buf[2048];
40 ctftests_lookup_cb_t *clc = arg;
41
42 if (ctf_type_name(clc->clc_fp, id, buf, sizeof (buf)) == NULL)
43 return (0);
44
45 if (strcmp(buf, clc->clc_name) != 0)
46 return (0);
47
48 clc->clc_id = id;
49 return (1);
50 }
51
52 /*
53 * This is a variant on the classic ctf_lookup_by_name(). ctf_lookup_by_name()
54 * skips qualifiers, which makes sense given what the consumers of it are trying
55 * to do. However, that's not what we want here. So instead we basically have to
56 * walk the type table.
57 */
58 static ctf_id_t
ctftest_lookup_type(ctf_file_t * fp,const char * name)59 ctftest_lookup_type(ctf_file_t *fp, const char *name)
60 {
61 ctftests_lookup_cb_t clc;
62
63 clc.clc_fp = fp;
64 clc.clc_id = CTF_ERR;
65 clc.clc_name = name;
66
67 (void) ctf_type_iter(fp, B_TRUE, ctftest_lookup_type_cb, &clc);
68 return (clc.clc_id);
69 }
70
71 static int
ctftest_lookup_object_cb(const char * obj,ctf_id_t type,ulong_t idx,void * arg)72 ctftest_lookup_object_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
73 {
74 ctftests_lookup_cb_t *clc = arg;
75
76 if (strcmp(obj, clc->clc_name) == 0) {
77 clc->clc_id = type;
78 return (1);
79 }
80
81 return (0);
82 }
83
84 static ctf_id_t
ctftest_lookup_symbol(ctf_file_t * fp,const char * name)85 ctftest_lookup_symbol(ctf_file_t *fp, const char *name)
86 {
87 ctftests_lookup_cb_t clc;
88
89 clc.clc_fp = fp;
90 clc.clc_id = CTF_ERR;
91 clc.clc_name = name;
92
93 (void) ctf_object_iter(fp, ctftest_lookup_object_cb, &clc);
94 return (clc.clc_id);
95 }
96
97 typedef struct ctf_function_cb {
98 const char *cfc_name;
99 ulong_t *cfc_symp;
100 ctf_funcinfo_t *cfc_fip;
101 } ctf_function_cb_t;
102
103 static int
ctftest_lookup_function_cb(const char * name,ulong_t symidx,ctf_funcinfo_t * fip,void * arg)104 ctftest_lookup_function_cb(const char *name, ulong_t symidx,
105 ctf_funcinfo_t *fip, void *arg)
106 {
107 ctf_function_cb_t *cfc = arg;
108 if (strcmp(name, cfc->cfc_name) != 0)
109 return (0);
110
111 *cfc->cfc_symp = symidx;
112 *cfc->cfc_fip = *fip;
113
114 return (1);
115 }
116
117 /*
118 * Note, this function finds the first one with a matching name. This must not
119 * be used when performing searches where a given name may occur more than once.
120 */
121 static boolean_t
ctftest_lookup_function(ctf_file_t * fp,const char * name,ulong_t * symp,ctf_funcinfo_t * fip)122 ctftest_lookup_function(ctf_file_t *fp, const char *name, ulong_t *symp,
123 ctf_funcinfo_t *fip)
124 {
125 ctf_function_cb_t cfc;
126
127 *symp = 0;
128 cfc.cfc_name = name;
129 cfc.cfc_symp = symp;
130 cfc.cfc_fip = fip;
131 (void) ctf_function_iter(fp, ctftest_lookup_function_cb, &cfc);
132 return (*symp == 0 ? B_FALSE : B_TRUE);
133 }
134
135 boolean_t
ctftest_check_numbers(ctf_file_t * fp,const check_number_t * tests)136 ctftest_check_numbers(ctf_file_t *fp, const check_number_t *tests)
137 {
138 uint_t i;
139 boolean_t ret = B_TRUE;
140
141 for (i = 0; tests[i].cn_tname != NULL; i++) {
142 ctf_id_t id;
143 ctf_encoding_t enc;
144
145 if (ctftest_skip(tests[i].cn_skips)) {
146 warnx("skipping check numbers test %s due to known "
147 "compiler issue", tests[i].cn_tname);
148 continue;
149 }
150
151 id = ctftest_lookup_type(fp, tests[i].cn_tname);
152 if (id == CTF_ERR) {
153 warnx("failed to look up %s", tests[i].cn_tname);
154 ret = B_FALSE;
155 continue;
156 }
157
158 if (ctf_type_kind(fp, id) != tests[i].cn_kind) {
159 warnx("type kind mismatch for %s: got %u, expected %u",
160 tests[i].cn_tname, ctf_type_kind(fp, id),
161 tests[i].cn_kind);
162 ret = B_FALSE;
163 continue;
164 }
165
166 if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) {
167 warnx("failed to get type encoding for %s: %s",
168 tests[i].cn_tname, ctf_errmsg(ctf_errno(fp)));
169 ret = B_FALSE;
170 continue;
171 }
172
173 if (enc.cte_format != tests[i].cn_flags) {
174 warnx("encoding flags mismatch for %s: got 0x%x, "
175 "expected 0x%x", tests[i].cn_tname, enc.cte_format,
176 tests[i].cn_flags);
177 ret = B_FALSE;
178 continue;
179 }
180
181 if (enc.cte_offset != tests[i].cn_offset) {
182 warnx("encoding offset mismatch for %s: got 0x%x, "
183 "expected 0x%x", tests[i].cn_tname, enc.cte_offset,
184 tests[i].cn_offset);
185 ret = B_FALSE;
186 continue;
187 }
188
189 if (enc.cte_bits != tests[i].cn_size) {
190 warnx("encoding size mismatch for %s: got 0x%x, "
191 "expected 0x%x", tests[i].cn_tname, enc.cte_bits,
192 tests[i].cn_size);
193 ret = B_FALSE;
194 continue;
195 }
196 }
197
198 return (ret);
199 }
200
201 typedef struct ctftests_symbol_cb {
202 ctf_file_t *csc_fp;
203 boolean_t csc_ret;
204 const check_symbol_t *csc_tests;
205 } ctftest_symbol_cb_t;
206
207 static int
ctftest_check_symbol_cb(const char * obj,ctf_id_t type,ulong_t idx,void * arg)208 ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
209 {
210 ctftest_symbol_cb_t *cb = arg;
211 const check_symbol_t *tests = cb->csc_tests;
212 ctf_file_t *fp = cb->csc_fp;
213 uint_t i;
214
215 for (i = 0; tests[i].cs_symbol != NULL; i++) {
216 ctf_id_t id;
217
218 if (strcmp(obj, tests[i].cs_symbol) != 0)
219 continue;
220
221 id = ctftest_lookup_type(fp, tests[i].cs_type);
222 if (id == CTF_ERR) {
223 warnx("failed to lookup type %s for symbol %s",
224 tests[i].cs_type, tests[i].cs_symbol);
225 cb->csc_ret = B_FALSE;
226 return (0);
227 }
228
229 if (id != type) {
230 warnx("type mismatch for symbol %s, has type id %ld"
231 ", but specified type %s has id %ld",
232 tests[i].cs_symbol, type, tests[i].cs_type, id);
233 cb->csc_ret = B_FALSE;
234 return (0);
235 }
236 }
237
238 return (0);
239 }
240
241 boolean_t
ctftest_check_symbols(ctf_file_t * fp,const check_symbol_t * tests)242 ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests)
243 {
244 ctftest_symbol_cb_t cb;
245
246 cb.csc_fp = fp;
247 cb.csc_ret = B_TRUE;
248 cb.csc_tests = tests;
249 if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0)
250 return (B_FALSE);
251 return (cb.csc_ret);
252 }
253
254
255 boolean_t
ctftest_check_descent(const char * symbol,ctf_file_t * fp,const check_descent_t * tests,boolean_t quiet)256 ctftest_check_descent(const char *symbol, ctf_file_t *fp,
257 const check_descent_t *tests, boolean_t quiet)
258 {
259 ctf_id_t base;
260 uint_t layer = 0;
261
262 /*
263 * First, find the initial type of the symbol.
264 */
265 base = ctftest_lookup_symbol(fp, symbol);
266 if (base == CTF_ERR) {
267 warnx("failed to lookup type for symbol %s", symbol);
268 return (B_FALSE);
269 }
270
271 while (tests->cd_tname != NULL) {
272 ctf_id_t tid;
273 int kind;
274 ctf_arinfo_t ari;
275
276 if (base == CTF_ERR) {
277 if (!quiet) {
278 warnx("encountered non-reference type at layer "
279 "%u while still expecting type %s for "
280 "symbol %s", layer,
281 tests->cd_tname, symbol);
282 }
283 return (B_FALSE);
284 }
285
286 tid = ctftest_lookup_type(fp, tests->cd_tname);
287 if (tid == CTF_ERR) {
288 if (!quiet) {
289 warnx("failed to lookup type %s",
290 tests->cd_tname);
291 }
292 return (B_FALSE);
293 }
294
295 if (tid != base) {
296 if (!quiet) {
297 warnx("type mismatch at layer %u: found "
298 "id %ld, but expecting type id %ld for "
299 "type %s, symbol %s", layer, base, tid,
300 tests->cd_tname, symbol);
301 }
302 return (B_FALSE);
303 }
304
305 kind = ctf_type_kind(fp, base);
306 if (kind != tests->cd_kind) {
307 if (!quiet) {
308 warnx("type kind mismatch at layer %u: found "
309 "kind %u, but expected kind %u for %s, "
310 "symbol %s", layer, kind, tests->cd_kind,
311 tests->cd_tname, symbol);
312 }
313 return (B_FALSE);
314 }
315
316 switch (kind) {
317 case CTF_K_ARRAY:
318 if (ctf_array_info(fp, base, &ari) == CTF_ERR) {
319 if (!quiet) {
320 warnx("failed to lookup array info at "
321 "layer %ld for type %s, "
322 "symbol %s: %s", base,
323 tests->cd_tname, symbol,
324 ctf_errmsg(ctf_errno(fp)));
325 }
326 return (B_FALSE);
327 }
328
329 if (tests->cd_nents != ari.ctr_nelems) {
330 if (!quiet) {
331 warnx("array element mismatch at layer "
332 "%u for type %s, symbol %s: found "
333 "%u, expected %u", layer,
334 tests->cd_tname, symbol,
335 ari.ctr_nelems, tests->cd_nents);
336 }
337 return (B_FALSE);
338 }
339
340 tid = ctftest_lookup_type(fp, tests->cd_contents);
341 if (tid == CTF_ERR) {
342 if (!quiet) {
343 warnx("failed to look up type %s",
344 tests->cd_contents);
345 }
346 return (B_FALSE);
347 }
348
349 if (ari.ctr_contents != tid) {
350 if (!quiet) {
351 warnx("array contents mismatch at "
352 "layer %u for type %s, symbol %s: "
353 "found %ld, expected %s/%ld",
354 layer, tests->cd_tname,
355 symbol, ari.ctr_contents,
356 tests->cd_contents, tid);
357 }
358 return (B_FALSE);
359 }
360 base = ari.ctr_contents;
361 break;
362 default:
363 base = ctf_type_reference(fp, base);
364 break;
365 }
366
367 tests++;
368 layer++;
369 }
370
371 if (base != CTF_ERR) {
372 if (!quiet) {
373 warnx("found additional type %ld in chain, "
374 "but expected no more", base);
375 }
376 return (B_FALSE);
377 }
378
379 return (B_TRUE);
380 }
381
382 int
ctftest_check_enum_count(const char * name,int value,void * arg)383 ctftest_check_enum_count(const char *name, int value, void *arg)
384 {
385 uint_t *u = arg;
386 *u = *u + 1;
387 return (0);
388 }
389
390 int
ctftest_check_enum_value(const char * name,int value,void * arg)391 ctftest_check_enum_value(const char *name, int value, void *arg)
392 {
393 uint_t i;
394 const check_enum_t *enums = arg;
395
396 for (i = 0; enums[i].ce_name != NULL; i++) {
397 if (strcmp(enums[i].ce_name, name) != 0)
398 continue;
399 if (enums[i].ce_value == (int64_t)value)
400 return (0);
401 warnx("enum %s value mismatch: found %d, expected %" PRId64,
402 name, value, enums[i].ce_value);
403 return (1);
404 }
405
406 warnx("found no matching entry for enum member %s", name);
407 return (1);
408 }
409
410 boolean_t
ctftest_check_enum(const char * type,ctf_file_t * fp,const check_enum_t * enums)411 ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums)
412 {
413 int ret;
414 uint_t tcount, ecount;
415 ctf_id_t base;
416
417 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
418 warnx("Failed to look up type %s", type);
419 return (B_FALSE);
420 }
421
422 if (ctf_type_kind(fp, base) != CTF_K_ENUM) {
423 warnx("%s is not an enum", type);
424 return (B_FALSE);
425 }
426
427 /*
428 * First count how many entries we have.
429 */
430 tcount = 0;
431 while (enums[tcount].ce_name != NULL) {
432 tcount++;
433 }
434
435 ecount = 0;
436 if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) {
437 warnx("failed to walk enum %s: %s", type,
438 ctf_errmsg(ctf_errno(fp)));
439 return (B_FALSE);
440 }
441
442 if (tcount != ecount) {
443 warnx("enum value mismatch: expected %u values, but found %u",
444 tcount, ecount);
445 return (B_FALSE);
446 }
447
448 if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value,
449 (void *)enums)) != 0) {
450 if (ret == -1) {
451 warnx("failed to walk enum %s: %s", type,
452 ctf_errmsg(ctf_errno(fp)));
453 }
454 return (B_FALSE);
455 }
456
457 return (B_TRUE);
458 }
459
460 int
ctftest_check_member_count(const char * mname,ctf_id_t mtype,ulong_t bitoff,void * arg)461 ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff,
462 void *arg)
463 {
464 uint_t *countp = arg;
465 *countp = *countp + 1;
466 return (0);
467 }
468
469 int
ctftest_check_members_cb(const char * mname,ctf_id_t mtype,ulong_t bitoff,void * arg)470 ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff,
471 void *arg)
472 {
473 uint_t i;
474 const ctftest_member_cb_t *cmc = arg;
475 const check_member_t *members = cmc->cmc_members;
476 ctf_file_t *fp = cmc->cmc_fp;
477
478 for (i = 0; members[i].cm_name != NULL; i++) {
479 boolean_t bad = B_FALSE;
480 char buf[2048];
481
482 if (strcmp(mname, members[i].cm_name) != 0)
483 continue;
484
485 if (bitoff != members[i].cm_offset) {
486 warnx("member %s of type %s has mismatched bit offset: "
487 "found %lu, expected %lu", mname, cmc->cmc_name,
488 bitoff, members[i].cm_offset);
489 bad = B_TRUE;
490 }
491
492 if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) {
493 warnx("failed to obtain type name for member %s: %s",
494 mname, ctf_errmsg(ctf_errno(fp)));
495 bad = B_TRUE;
496 } else if (strcmp(buf, members[i].cm_type) != 0) {
497 warnx("member %s has bad type, found %s, expected %s",
498 mname, buf, members[i].cm_type);
499 bad = B_TRUE;
500 }
501
502 return (bad ? 1 : 0);
503 }
504
505 warnx("found no matching entry for member %s of type %s", mname,
506 cmc->cmc_name);
507 return (1);
508 }
509
510 boolean_t
ctftest_check_members(const char * type,ctf_file_t * fp,int kind,size_t size,const check_member_t * members)511 ctftest_check_members(const char *type, ctf_file_t *fp, int kind,
512 size_t size, const check_member_t *members)
513 {
514 int ret;
515 uint_t tcount, mcount;
516 ctf_id_t base;
517 ctftest_member_cb_t cmc;
518
519 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
520 warnx("failed to look up type %s", type);
521 return (B_FALSE);
522 }
523
524 if (ctf_type_kind(fp, base) != kind) {
525 warnx("%s has kind %s, expected %s", type,
526 ctf_kind_name(fp, ctf_type_kind(fp, base)),
527 ctf_kind_name(fp, kind));
528 return (B_FALSE);
529 }
530
531 if (size != ctf_type_size(fp, base)) {
532 warnx("%s has bad size, expected %zu, found %zd",
533 type, size, ctf_type_size(fp, base));
534 return (B_FALSE);
535 }
536
537 /*
538 * First count how many entries we have.
539 */
540 tcount = 0;
541 while (members[tcount].cm_name != NULL) {
542 tcount++;
543 }
544
545 mcount = 0;
546 if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) !=
547 0) {
548 warnx("failed to walk members of %s: %s", type,
549 ctf_errmsg(ctf_errno(fp)));
550 return (B_FALSE);
551 }
552
553 if (tcount != mcount) {
554 warnx("type member mismatch: expected %u values, but found %u",
555 tcount, mcount);
556 return (B_FALSE);
557 }
558
559 cmc.cmc_fp = fp;
560 cmc.cmc_members = members;
561 cmc.cmc_name = type;
562 if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb,
563 &cmc)) != 0) {
564 if (ret == -1) {
565 warnx("failed to walk type %s: %s", type,
566 ctf_errmsg(ctf_errno(fp)));
567 }
568 return (B_FALSE);
569 }
570
571 return (B_TRUE);
572 }
573
574 boolean_t
ctftest_check_function(const char * symbol,ctf_file_t * fp,const char * rtype,uint_t nargs,uint_t flags,const char ** argv)575 ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype,
576 uint_t nargs, uint_t flags, const char **argv)
577 {
578 ulong_t sym;
579 ctf_funcinfo_t fi;
580 uint_t i;
581 boolean_t ret = B_TRUE;
582 ctf_id_t *args;
583 char buf[2048];
584
585
586 if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) {
587 warnx("failed to look up function %s", symbol);
588 return (B_FALSE);
589 }
590
591 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
592 warnx("failed to lookup return type name for function %s",
593 symbol);
594 ret = B_FALSE;
595 } else if (strcmp(rtype, buf) != 0) {
596 warnx("return type has wrong type: found %s, expected %s",
597 buf, rtype);
598 ret = B_FALSE;
599 }
600
601 if (nargs != fi.ctc_argc) {
602 warnx("function argument mismatch: found %u, expected %u",
603 fi.ctc_argc, nargs);
604 ret = B_FALSE;
605 }
606
607 if (flags != fi.ctc_flags) {
608 warnx("function flags mismatch, found 0x%x, expected 0x%x",
609 fi.ctc_flags, flags);
610 ret = B_FALSE;
611 }
612
613 if (!ret || fi.ctc_argc == 0) {
614 return (ret);
615 }
616
617 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
618 warnx("failed to allocate memory for function arguments");
619 return (B_FALSE);
620 }
621
622 if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) {
623 warnx("failed to get function information: %s",
624 ctf_errmsg(ctf_errno(fp)));
625 free(args);
626 return (B_FALSE);
627 }
628
629 for (i = 0; i < fi.ctc_argc; i++) {
630 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
631 warnx("failed to obtain type name for argument %u: %s",
632 i, ctf_errmsg(ctf_errno(fp)));
633 ret = B_FALSE;
634 break;
635 }
636
637 if (strcmp(buf, argv[i]) != 0) {
638 warnx("argument %u has wrong type: found %s, "
639 "expected %s", i, buf, argv[i]);
640 ret = B_FALSE;
641 break;
642 }
643 }
644
645 free(args);
646 return (ret);
647 }
648
649 boolean_t
ctftest_check_fptr(const char * type,ctf_file_t * fp,const char * rtype,uint_t nargs,uint_t flags,const char ** argv)650 ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype,
651 uint_t nargs, uint_t flags, const char **argv)
652 {
653 ctf_id_t tid;
654 ctf_funcinfo_t fi;
655 uint_t i;
656 boolean_t ret = B_TRUE;
657 ctf_id_t *args;
658 char buf[2048];
659
660
661 if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
662 warnx("failed to look up type %s: %s", type,
663 ctf_errmsg(ctf_errno(fp)));
664 return (B_FALSE);
665 }
666
667 /*
668 * Perform two CTF type resolves, one for the function pointer and one
669 * for the typedef that gets passed in.
670 */
671 if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) {
672 warnx("failed to convert type %s to base type: %s", type,
673 ctf_errmsg(ctf_errno(fp)));
674 return (B_FALSE);
675 }
676
677 if (ctf_type_kind(fp, tid) == CTF_K_POINTER &&
678 (tid = ctf_type_reference(fp, tid)) == CTF_ERR) {
679 warnx("failed to convert type %s to base type: %s", type,
680 ctf_errmsg(ctf_errno(fp)));
681 return (B_FALSE);
682 }
683
684 if (ctf_func_info_by_id(fp, tid, &fi) != 0) {
685 warnx("failed to get function information for type %s: %s",
686 type, ctf_errmsg(ctf_errno(fp)));
687 return (B_FALSE);
688 }
689
690 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
691 warnx("failed to lookup return type name for function %s",
692 type);
693 ret = B_FALSE;
694 } else if (strcmp(rtype, buf) != 0) {
695 warnx("return type has wrong type: found %s, expected %s",
696 buf, rtype);
697 ret = B_FALSE;
698 }
699
700 if (nargs != fi.ctc_argc) {
701 warnx("function argument mismatch: found %u, expected %u",
702 fi.ctc_argc, nargs);
703 ret = B_FALSE;
704 }
705
706 if (flags != fi.ctc_flags) {
707 warnx("function flags mismatch, found 0x%x, expected 0x%x",
708 fi.ctc_flags, flags);
709 ret = B_FALSE;
710 }
711
712 if (!ret || fi.ctc_argc == 0) {
713 return (ret);
714 }
715
716 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
717 warnx("failed to allocate memory for function arguments");
718 return (B_FALSE);
719 }
720
721 if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) {
722 warnx("failed to get function information: %s",
723 ctf_errmsg(ctf_errno(fp)));
724 free(args);
725 return (B_FALSE);
726 }
727
728 for (i = 0; i < fi.ctc_argc; i++) {
729 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
730 warnx("failed to obtain type name for argument %u: %s",
731 i, ctf_errmsg(ctf_errno(fp)));
732 ret = B_FALSE;
733 break;
734 }
735
736 if (strcmp(buf, argv[i]) != 0) {
737 warnx("argument %u has wrong type: found %s, "
738 "expected %s", i, buf, argv[i]);
739 ret = B_FALSE;
740 break;
741 }
742 }
743
744 free(args);
745 return (ret);
746 }
747
748 boolean_t
ctftest_check_size(const char * type,ctf_file_t * fp,size_t size)749 ctftest_check_size(const char *type, ctf_file_t *fp, size_t size)
750 {
751 ctf_id_t base;
752
753 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
754 warnx("Failed to look up type %s", type);
755 return (B_FALSE);
756 }
757
758 if (size != ctf_type_size(fp, base)) {
759 warnx("%s has bad size, expected %zu, found %zd",
760 type, size, ctf_type_size(fp, base));
761 return (B_FALSE);
762 }
763
764 return (B_TRUE);
765 }
766
767 typedef struct ctftest_duplicates {
768 ctf_file_t *ctd_fp;
769 char **ctd_names;
770 size_t ctd_len;
771 size_t ctd_curent;
772 boolean_t ctd_ret;
773 } ctftest_duplicates_t;
774
775 static int
ctftest_duplicates_cb(ctf_id_t id,boolean_t root,void * arg)776 ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg)
777 {
778 char buf[2048];
779 ctftest_duplicates_t *dup = arg;
780 size_t i;
781
782 if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) {
783 warnx("failed to lookup name for id %ld", id);
784 dup->ctd_ret = B_FALSE;
785 return (1);
786 }
787
788 for (i = 0; i < dup->ctd_curent; i++) {
789 if (strcmp(buf, dup->ctd_names[i]) == 0) {
790 warnx("encountered duplicate type '%s'", buf);
791 dup->ctd_ret = B_FALSE;
792 /*
793 * Don't break out of the loop and keep going in case we
794 * find another duplicate.
795 */
796 return (0);
797 }
798 }
799
800 if (dup->ctd_curent == dup->ctd_len) {
801 char **n;
802 size_t newlen = dup->ctd_len * 2;
803
804 n = recallocarray(dup->ctd_names, dup->ctd_len, newlen,
805 sizeof (char *));
806 if (n == NULL) {
807 warnx("failed to resize type name array");
808 dup->ctd_ret = B_FALSE;
809 return (1);
810 }
811
812 dup->ctd_names = n;
813 dup->ctd_len = newlen;
814 }
815
816 dup->ctd_names[dup->ctd_curent] = strdup(buf);
817 if (dup->ctd_names[dup->ctd_curent] == NULL) {
818 warn("failed to duplicate type name");
819 dup->ctd_ret = B_FALSE;
820 return (1);
821 }
822 dup->ctd_curent++;
823
824 return (0);
825 }
826
827 boolean_t
ctftest_duplicates(ctf_file_t * fp)828 ctftest_duplicates(ctf_file_t *fp)
829 {
830 size_t i;
831 ctftest_duplicates_t d;
832
833 bzero(&d, sizeof (d));
834 d.ctd_fp = fp;
835 d.ctd_len = 4;
836 d.ctd_ret = B_TRUE;
837 d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *));
838 if (d.ctd_names == NULL) {
839 warnx("failed to allocate duplicate name storage");
840 return (B_FALSE);
841 }
842
843 (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d);
844
845 for (i = 0; i < d.ctd_curent; i++) {
846 free(d.ctd_names[i]);
847 }
848 free(d.ctd_names);
849
850 return (d.ctd_ret);
851 }
852
853 boolean_t
ctftest_skip(check_skip_t skip)854 ctftest_skip(check_skip_t skip)
855 {
856 const char *compiler;
857
858 if (skip == 0) {
859 return (B_FALSE);
860 }
861
862 compiler = getenv("ctf_cc_type");
863 if (compiler == NULL) {
864 return (B_FALSE);
865 }
866
867 if ((skip & SKIP_CLANG) != 0 && strcmp(compiler, "clang") == 0)
868 return (B_TRUE);
869
870 return (B_FALSE);
871 }
872