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