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