rm code review
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
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
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
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
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
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
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
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 id = ctftest_lookup_type(fp, tests[i].cn_tname);
146 if (id == CTF_ERR) {
147 warnx("failed to look up %s", tests[i].cn_tname);
148 ret = B_FALSE;
149 continue;
150 }
151
152 if (ctf_type_kind(fp, id) != tests[i].cn_kind) {
153 warnx("type kind mismatch for %s: got %u, expected %u",
154 tests[i].cn_tname, ctf_type_kind(fp, id),
155 tests[i].cn_kind);
156 ret = B_FALSE;
157 continue;
158 }
159
160 if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) {
161 warnx("failed to get type encoding for %s: %s",
162 tests[i].cn_tname, ctf_errmsg(ctf_errno(fp)));
163 ret = B_FALSE;
164 continue;
165 }
166
167 if (enc.cte_format != tests[i].cn_flags) {
168 warnx("encoding flags mismatch for %s: got 0x%x, "
169 "expected 0x%x", tests[i].cn_tname, enc.cte_format,
170 tests[i].cn_flags);
171 ret = B_FALSE;
172 continue;
173 }
174
175 if (enc.cte_offset != tests[i].cn_offset) {
176 warnx("encoding offset mismatch for %s: got 0x%x, "
177 "expected 0x%x", tests[i].cn_tname, enc.cte_offset,
178 tests[i].cn_offset);
179 ret = B_FALSE;
180 continue;
181 }
182
183 if (enc.cte_bits != tests[i].cn_size) {
184 warnx("encoding size mismatch for %s: got 0x%x, "
185 "expected 0x%x", tests[i].cn_tname, enc.cte_bits,
186 tests[i].cn_size);
187 ret = B_FALSE;
188 continue;
189 }
190 }
191
192 return (ret);
193 }
194
195 typedef struct ctftests_symbol_cb {
196 ctf_file_t *csc_fp;
197 boolean_t csc_ret;
198 const check_symbol_t *csc_tests;
199 } ctftest_symbol_cb_t;
200
201 static int
202 ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg)
203 {
204 ctftest_symbol_cb_t *cb = arg;
205 const check_symbol_t *tests = cb->csc_tests;
206 ctf_file_t *fp = cb->csc_fp;
207 uint_t i;
208
209 for (i = 0; tests[i].cs_symbol != NULL; i++) {
210 ctf_id_t id;
211
212 if (strcmp(obj, tests[i].cs_symbol) != 0)
213 continue;
214
215 id = ctftest_lookup_type(fp, tests[i].cs_type);
216 if (id == CTF_ERR) {
217 warnx("failed to lookup type %s for symbol %s",
218 tests[i].cs_type, tests[i].cs_symbol);
219 cb->csc_ret = B_FALSE;
220 return (0);
221 }
222
223 if (id != type) {
224 warnx("type mismatch for symbol %s, has type id %u, "
225 "but specified type %s has id %u",
226 tests[i].cs_symbol, type, tests[i].cs_type, id);
227 cb->csc_ret = B_FALSE;
228 return (0);
229 }
230 }
231
232 return (0);
233 }
234
235 boolean_t
236 ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests)
237 {
238 ctftest_symbol_cb_t cb;
239
240 cb.csc_fp = fp;
241 cb.csc_ret = B_TRUE;
242 cb.csc_tests = tests;
243 if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0)
244 return (B_FALSE);
245 return (cb.csc_ret);
246 }
247
248
249 boolean_t
250 ctftest_check_descent(const char *symbol, ctf_file_t *fp,
251 const check_descent_t *tests, boolean_t quiet)
252 {
253 ctf_id_t base;
254 uint_t layer = 0;
255
256 /*
257 * First, find the initial type of the symbol.
258 */
259 base = ctftest_lookup_symbol(fp, symbol);
260 if (base == CTF_ERR) {
261 warnx("failed to lookup type for symbol %s", symbol);
262 return (B_FALSE);
263 }
264
265 while (tests->cd_tname != NULL) {
266 ctf_id_t tid;
267 int kind;
268 ctf_arinfo_t ari;
269
270 if (base == CTF_ERR) {
271 if (!quiet) {
272 warnx("encountered non-reference type at layer "
273 "%u while still expecting type %s for "
274 "symbol %s", layer,
275 tests->cd_tname, symbol);
276 }
277 return (B_FALSE);
278 }
279
280 tid = ctftest_lookup_type(fp, tests->cd_tname);
281 if (tid == CTF_ERR) {
282 if (!quiet) {
283 warnx("failed to lookup type %s",
284 tests->cd_tname);
285 }
286 return (B_FALSE);
287 }
288
289 if (tid != base) {
290 if (!quiet) {
291 warnx("type mismatch at layer %u: found id %u, "
292 "but expecting type id %u for type %s, "
293 "symbol %s", layer, base, tid,
294 tests->cd_tname, symbol);
295 }
296 return (B_FALSE);
297 }
298
299 kind = ctf_type_kind(fp, base);
300 if (kind != tests->cd_kind) {
301 if (!quiet) {
302 warnx("type kind mismatch at layer %u: found "
303 "kind %u, but expected kind %u for %s, "
304 "symbol %s", layer, kind, tests->cd_kind,
305 tests->cd_tname, symbol);
306 }
307 return (B_FALSE);
308 }
309
310 switch (kind) {
311 case CTF_K_ARRAY:
312 if (ctf_array_info(fp, base, &ari) == CTF_ERR) {
313 if (!quiet) {
314 warnx("failed to lookup array info at "
315 "layer %u for type %s, symbol "
316 "%s: %s", base, tests->cd_tname,
317 symbol, ctf_errmsg(ctf_errno(fp)));
318 }
319 return (B_FALSE);
320 }
321
322 if (tests->cd_nents != ari.ctr_nelems) {
323 if (!quiet) {
324 warnx("array element mismatch at layer "
325 "%u for type %s, symbol %s: found "
326 "%u, expected %u", layer,
327 tests->cd_tname, symbol,
328 ari.ctr_nelems, tests->cd_nents);
329 }
330 return (B_FALSE);
331 }
332
333 tid = ctftest_lookup_type(fp, tests->cd_contents);
334 if (tid == CTF_ERR) {
335 if (!quiet) {
336 warnx("failed to look up type %s",
337 tests->cd_contents);
338 }
339 return (B_FALSE);
340 }
341
342 if (ari.ctr_contents != tid) {
343 if (!quiet) {
344 warnx("array contents mismatch at "
345 "layer %u for type %s, symbol %s: "
346 "found %u, expected %s/%u", layer,
347 tests->cd_tname, symbol,
348 ari.ctr_contents,
349 tests->cd_contents, tid);
350 }
351 return (B_FALSE);
352 }
353 base = ari.ctr_contents;
354 break;
355 default:
356 base = ctf_type_reference(fp, base);
357 break;
358 }
359
360 tests++;
361 layer++;
362 }
363
364 if (base != CTF_ERR) {
365 if (!quiet) {
366 warnx("found additional type %u in chain, "
367 "but expected no more", base);
368 }
369 return (B_FALSE);
370 }
371
372 return (B_TRUE);
373 }
374
375 int
376 ctftest_check_enum_count(const char *name, int value, void *arg)
377 {
378 uint_t *u = arg;
379 *u = *u + 1;
380 return (0);
381 }
382
383 int
384 ctftest_check_enum_value(const char *name, int value, void *arg)
385 {
386 uint_t i;
387 const check_enum_t *enums = arg;
388
389 for (i = 0; enums[i].ce_name != NULL; i++) {
390 if (strcmp(enums[i].ce_name, name) != 0)
391 continue;
392 if (enums[i].ce_value == (int64_t)value)
393 return (0);
394 warnx("enum %s value mismatch: found %d, expected %" PRId64,
395 name, value, enums[i].ce_value);
396 return (1);
397 }
398
399 warnx("found no matching entry for enum member %s", name);
400 return (1);
401 }
402
403 boolean_t
404 ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums)
405 {
406 int ret;
407 uint_t tcount, ecount;
408 ctf_id_t base;
409
410 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
411 warnx("Failed to look up type %s", type);
412 return (B_FALSE);
413 }
414
415 if (ctf_type_kind(fp, base) != CTF_K_ENUM) {
416 warnx("%s is not an enum", type);
417 return (B_FALSE);
418 }
419
420 /*
421 * First count how many entries we have.
422 */
423 tcount = 0;
424 while (enums[tcount].ce_name != NULL) {
425 tcount++;
426 }
427
428 ecount = 0;
429 if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) {
430 warnx("failed to walk enum %s: %s", type,
431 ctf_errmsg(ctf_errno(fp)));
432 return (B_FALSE);
433 }
434
435 if (tcount != ecount) {
436 warnx("enum value mismatch: expected %u values, but found %u",
437 tcount, ecount);
438 return (B_FALSE);
439 }
440
441 if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value,
442 (void *)enums)) != 0) {
443 if (ret == -1) {
444 warnx("failed to walk enum %s: %s", type,
445 ctf_errmsg(ctf_errno(fp)));
446 }
447 return (B_FALSE);
448 }
449
450 return (B_TRUE);
451 }
452
453 int
454 ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff,
455 void *arg)
456 {
457 uint_t *countp = arg;
458 *countp = *countp + 1;
459 return (0);
460 }
461
462 int
463 ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff,
464 void *arg)
465 {
466 uint_t i;
467 const ctftest_member_cb_t *cmc = arg;
468 const check_member_t *members = cmc->cmc_members;
469 ctf_file_t *fp = cmc->cmc_fp;
470
471 for (i = 0; members[i].cm_name != NULL; i++) {
472 boolean_t bad = B_FALSE;
473 char buf[2048];
474
475 if (strcmp(mname, members[i].cm_name) != 0)
476 continue;
477
478 if (bitoff != members[i].cm_offset) {
479 warnx("member %s of type %s has mismatched bit offset: "
480 "found %lu, expected %lu", mname, cmc->cmc_name,
481 bitoff, members[i].cm_offset);
482 bad = B_TRUE;
483 }
484
485 if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) {
486 warnx("failed to obtain type name for member %s",
487 mname, ctf_errmsg(ctf_errno(fp)));
488 bad = B_TRUE;
489 } else if (strcmp(buf, members[i].cm_type) != 0) {
490 warnx("member %s has bad type, found %s, expected %s",
491 mname, buf, members[i].cm_type);
492 bad = B_TRUE;
493 }
494
495 return (bad ? 1 : 0);
496 }
497
498 warnx("found no matching entry for member %s of type %s", mname,
499 cmc->cmc_name);
500 return (1);
501 }
502
503 boolean_t
504 ctftest_check_members(const char *type, ctf_file_t *fp, int kind,
505 size_t size, const check_member_t *members)
506 {
507 int ret;
508 uint_t tcount, mcount;
509 ctf_id_t base;
510 ctftest_member_cb_t cmc;
511
512 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
513 warnx("failed to look up type %s", type);
514 return (B_FALSE);
515 }
516
517 if (ctf_type_kind(fp, base) != kind) {
518 warnx("%s has kind %s, expected %s", type,
519 ctf_kind_name(fp, ctf_type_kind(fp, base)),
520 ctf_kind_name(fp, kind));
521 return (B_FALSE);
522 }
523
524 if (size != ctf_type_size(fp, base)) {
525 warnx("%s has bad size, expected %lu, found %lu",
526 type, size, ctf_type_size(fp, base));
527 return (B_FALSE);
528 }
529
530 /*
531 * First count how many entries we have.
532 */
533 tcount = 0;
534 while (members[tcount].cm_name != NULL) {
535 tcount++;
536 }
537
538 mcount = 0;
539 if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) !=
540 0) {
541 warnx("failed to walk members of %s: %s", type,
542 ctf_errmsg(ctf_errno(fp)));
543 return (B_FALSE);
544 }
545
546 if (tcount != mcount) {
547 warnx("type member mismatch: expected %u values, but found %u",
548 tcount, mcount);
549 return (B_FALSE);
550 }
551
552 cmc.cmc_fp = fp;
553 cmc.cmc_members = members;
554 cmc.cmc_name = type;
555 if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb,
556 &cmc)) != 0) {
557 if (ret == -1) {
558 warnx("failed to walk type %s: %s", type,
559 ctf_errmsg(ctf_errno(fp)));
560 }
561 return (B_FALSE);
562 }
563
564 return (B_TRUE);
565 }
566
567 boolean_t
568 ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype,
569 uint_t nargs, uint_t flags, const char **argv)
570 {
571 ulong_t sym;
572 ctf_funcinfo_t fi;
573 uint_t i;
574 boolean_t ret = B_TRUE;
575 ctf_id_t *args;
576 char buf[2048];
577
578
579 if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) {
580 warnx("failed to look up function %s", symbol);
581 return (B_FALSE);
582 }
583
584 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
585 warnx("failed to lookup return type name for function %s",
586 symbol);
587 ret = B_FALSE;
588 } else if (strcmp(rtype, buf) != 0) {
589 warnx("return type has wrong type: found %s, expected %s",
590 buf, rtype);
591 ret = B_FALSE;
592 }
593
594 if (nargs != fi.ctc_argc) {
595 warnx("function argument mismatch: found %u, expected %u",
596 fi.ctc_argc, nargs);
597 ret = B_FALSE;
598 }
599
600 if (flags != fi.ctc_flags) {
601 warnx("function flags mismatch, found 0x%x, expected 0x%x",
602 fi.ctc_flags, flags);
603 ret = B_FALSE;
604 }
605
606 if (!ret || fi.ctc_argc == 0) {
607 return (ret);
608 }
609
610 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
611 warnx("failed to allocate memory for function arguments");
612 return (B_FALSE);
613 }
614
615 if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) {
616 warnx("failed to get function information: %s",
617 ctf_errmsg(ctf_errno(fp)));
618 free(args);
619 return (B_FALSE);
620 }
621
622 for (i = 0; i < fi.ctc_argc; i++) {
623 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
624 warnx("failed to obtain type name for argument %u",
625 i, ctf_errmsg(ctf_errno(fp)));
626 ret = B_FALSE;
627 break;
628 }
629
630 if (strcmp(buf, argv[i]) != 0) {
631 warnx("argument %u has wrong type: found %s, "
632 "expected %s", i, buf, argv[i]);
633 ret = B_FALSE;
634 break;
635 }
636 }
637
638 free(args);
639 return (ret);
640 }
641
642 boolean_t
643 ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype,
644 uint_t nargs, uint_t flags, const char **argv)
645 {
646 ctf_id_t tid;
647 ctf_funcinfo_t fi;
648 uint_t i;
649 boolean_t ret = B_TRUE;
650 ctf_id_t *args;
651 char buf[2048];
652
653
654 if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) {
655 warnx("failed to look up type %s: %s", type,
656 ctf_errmsg(ctf_errno(fp)));
657 return (B_FALSE);
658 }
659
660 /*
661 * Perform two CTF type resolves, one for the function pointer and one
662 * for the typedef that gets passed in.
663 */
664 if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) {
665 warnx("failed to convert type %s to base type: %s", type,
666 ctf_errmsg(ctf_errno(fp)));
667 return (B_FALSE);
668 }
669
670 if (ctf_type_kind(fp, tid) == CTF_K_POINTER &&
671 (tid = ctf_type_reference(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_func_info_by_id(fp, tid, &fi) != 0) {
678 warnx("failed to get function information for type %s: %s",
679 type, ctf_errmsg(ctf_errno(fp)));
680 return (B_FALSE);
681 }
682
683 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) {
684 warnx("failed to lookup return type name for function %s",
685 type);
686 ret = B_FALSE;
687 } else if (strcmp(rtype, buf) != 0) {
688 warnx("return type has wrong type: found %s, expected %s",
689 buf, rtype);
690 ret = B_FALSE;
691 }
692
693 if (nargs != fi.ctc_argc) {
694 warnx("function argument mismatch: found %u, expected %u",
695 fi.ctc_argc, nargs);
696 ret = B_FALSE;
697 }
698
699 if (flags != fi.ctc_flags) {
700 warnx("function flags mismatch, found 0x%x, expected 0x%x",
701 fi.ctc_flags, flags);
702 ret = B_FALSE;
703 }
704
705 if (!ret || fi.ctc_argc == 0) {
706 return (ret);
707 }
708
709 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) {
710 warnx("failed to allocate memory for function arguments");
711 return (B_FALSE);
712 }
713
714 if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) {
715 warnx("failed to get function information: %s",
716 ctf_errmsg(ctf_errno(fp)));
717 free(args);
718 return (B_FALSE);
719 }
720
721 for (i = 0; i < fi.ctc_argc; i++) {
722 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) {
723 warnx("failed to obtain type name for argument %u",
724 i, ctf_errmsg(ctf_errno(fp)));
725 ret = B_FALSE;
726 break;
727 }
728
729 if (strcmp(buf, argv[i]) != 0) {
730 warnx("argument %u has wrong type: found %s, "
731 "expected %s", i, buf, argv[i]);
732 ret = B_FALSE;
733 break;
734 }
735 }
736
737 free(args);
738 return (ret);
739 }
740
741 boolean_t
742 ctftest_check_size(const char *type, ctf_file_t *fp, size_t size)
743 {
744 ctf_id_t base;
745
746 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) {
747 warnx("Failed to look up type %s", type);
748 return (B_FALSE);
749 }
750
751 if (size != ctf_type_size(fp, base)) {
752 warnx("%s has bad size, expected %lu, found %lu",
753 type, size, ctf_type_size(fp, base));
754 return (B_FALSE);
755 }
756
757 return (B_TRUE);
758 }
759
760 typedef struct ctftest_duplicates {
761 ctf_file_t *ctd_fp;
762 char **ctd_names;
763 size_t ctd_len;
764 size_t ctd_curent;
765 boolean_t ctd_ret;
766 } ctftest_duplicates_t;
767
768 static int
769 ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg)
770 {
771 char buf[2048];
772 ctftest_duplicates_t *dup = arg;
773 size_t i;
774
775 if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) {
776 warnx("failed to lookup name for id %ld", id);
777 dup->ctd_ret = B_FALSE;
778 return (1);
779 }
780
781 for (i = 0; i < dup->ctd_curent; i++) {
782 if (strcmp(buf, dup->ctd_names[i]) == 0) {
783 warnx("encountered duplicate type '%s'", buf);
784 dup->ctd_ret = B_FALSE;
785 /*
786 * Don't break out of the loop and keep going in case we
787 * find another duplicate.
788 */
789 return (0);
790 }
791 }
792
793 if (dup->ctd_curent == dup->ctd_len) {
794 char **n;
795 size_t newlen = dup->ctd_len * 2;
796
797 n = recallocarray(dup->ctd_names, dup->ctd_len, newlen,
798 sizeof (char *));
799 if (n == NULL) {
800 warnx("failed to resize type name array");
801 dup->ctd_ret = B_FALSE;
802 return (1);
803 }
804
805 dup->ctd_names = n;
806 dup->ctd_len = newlen;
807 }
808
809 dup->ctd_names[dup->ctd_curent] = strdup(buf);
810 if (dup->ctd_names[dup->ctd_curent] == NULL) {
811 warn("failed to duplicate type name");
812 dup->ctd_ret = B_FALSE;
813 return (1);
814 }
815 dup->ctd_curent++;
816
817 return (0);
818 }
819
820 boolean_t
821 ctftest_duplicates(ctf_file_t *fp)
822 {
823 size_t i;
824 ctftest_duplicates_t d;
825
826 bzero(&d, sizeof (d));
827 d.ctd_fp = fp;
828 d.ctd_len = 4;
829 d.ctd_ret = B_TRUE;
830 d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *));
831 if (d.ctd_names == NULL) {
832 warnx("failed to allocate duplicate name storage");
833 return (B_FALSE);
834 }
835
836 (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d);
837
838 for (i = 0; i < d.ctd_curent; i++) {
839 free(d.ctd_names[i]);
840 }
841 free(d.ctd_names);
842
843 return (d.ctd_ret);
844 }
--- EOF ---