1/*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source.  A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12/*
13 * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
14 */
15
16/*
17 * The following is a basic overview of how we diff types in containers (the
18 * generally interesting part of diff, and what's used by merge). We maintain
19 * two mapping tables, a table of forward mappings (src->dest), and a reverse
20 * mapping (dest->src). Both are initialized to contain no mapping, and can also
21 * be updated to contain a negative mapping.
22 *
23 * What we do first is iterate over each type in the src container, and compare
24 * it with a type in the destination container. This may involve doing recursive
25 * comparisons -- which can involve cycles. To deal with this, whenever we
26 * encounter something which may be cyclic, we insert a guess. In other words,
27 * we assume that it may be true. This is necessary for the classic case of the
28 * following structure:
29 *
30 * struct foo {
31 *	struct foo *foo_next;
32 * };
33 *
34 * If it turns out that we were wrong, we discard our guesses.
35 *
36 * If we find that a given type in src has no corresponding entry in dst, we
37 * then mark its map as CTF_ERR (-1) to indicate that it has *no* match, as
38 * opposed to the default value of 0, which indicates an unknown match.
39 * Once we've done the first iteration through src, we know at that point in
40 * time whether everything in dst is similar or not and can simply walk over it
41 * and don't have to do any additional checks.
42 */
43
44#include <libctf.h>
45#include <ctf_impl.h>
46#include <sys/debug.h>
47
48typedef struct ctf_diff_func {
49	const char *cdf_name;
50	ulong_t cdf_symidx;
51	ulong_t cdf_matchidx;
52} ctf_diff_func_t;
53
54typedef struct ctf_diff_obj {
55	const char *cdo_name;
56	ulong_t cdo_symidx;
57	ctf_id_t cdo_id;
58	ulong_t cdo_matchidx;
59} ctf_diff_obj_t;
60
61typedef struct ctf_diff_guess {
62	struct ctf_diff_guess *cdg_next;
63	ctf_id_t cdg_iid;
64	ctf_id_t cdg_oid;
65} ctf_diff_guess_t;
66
67/* typedef in libctf.h */
68struct ctf_diff {
69	uint_t cds_flags;
70	boolean_t cds_tvalid;	/* types valid */
71	ctf_file_t *cds_ifp;
72	ctf_file_t *cds_ofp;
73	ctf_id_t *cds_forward;
74	ctf_id_t *cds_reverse;
75	size_t cds_fsize;
76	size_t cds_rsize;
77	ctf_diff_type_f cds_func;
78	ctf_diff_guess_t *cds_guess;
79	void *cds_arg;
80	uint_t cds_nifuncs;
81	uint_t cds_nofuncs;
82	uint_t cds_nextifunc;
83	uint_t cds_nextofunc;
84	ctf_diff_func_t *cds_ifuncs;
85	ctf_diff_func_t *cds_ofuncs;
86	boolean_t cds_ffillip;
87	boolean_t cds_fvalid;
88	uint_t cds_niobj;
89	uint_t cds_noobj;
90	uint_t cds_nextiobj;
91	uint_t cds_nextoobj;
92	ctf_diff_obj_t *cds_iobj;
93	ctf_diff_obj_t *cds_oobj;
94	boolean_t cds_ofillip;
95	boolean_t cds_ovalid;
96};
97
98#define	TINDEX(tid) (tid - 1)
99
100/*
101 * Team Diff
102 */
103static int ctf_diff_type(ctf_diff_t *, ctf_file_t *, ctf_id_t, ctf_file_t *,
104    ctf_id_t);
105
106static int
107ctf_diff_name(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
108{
109	const char *iname, *oname;
110	const ctf_type_t *itp, *otp;
111
112	if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
113		return (CTF_ERR);
114
115	if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
116		return (ctf_set_errno(ifp, iid));
117
118	iname = ctf_strptr(ifp, itp->ctt_name);
119	oname = ctf_strptr(ofp, otp->ctt_name);
120
121	if ((iname == NULL || oname == NULL) && (iname != oname))
122		return (B_TRUE);
123
124	/* Two anonymous names are the same */
125	if (iname == NULL && oname == NULL)
126		return (B_FALSE);
127
128	return (strcmp(iname, oname) == 0 ? B_FALSE: B_TRUE);
129}
130
131/*
132 * For floats and ints
133 */
134static int
135ctf_diff_number(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
136{
137	ctf_encoding_t ien, den;
138
139	if (ctf_type_encoding(ifp, iid, &ien) != 0)
140		return (CTF_ERR);
141
142	if (ctf_type_encoding(ofp, oid, &den) != 0)
143		return (ctf_set_errno(ifp, iid));
144
145	if (bcmp(&ien, &den, sizeof (ctf_encoding_t)) != 0)
146		return (B_TRUE);
147
148	return (B_FALSE);
149}
150
151/*
152 * Two typedefs are equivalent, if after we resolve a chain of typedefs, they
153 * point to equivalent types. This means that if a size_t is defined as follows:
154 *
155 * size_t -> ulong_t -> unsigned long
156 * size_t -> unsigned long
157 *
158 * That we'll ultimately end up treating them the same.
159 */
160static int
161ctf_diff_typedef(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid,
162    ctf_file_t *ofp, ctf_id_t oid)
163{
164	ctf_id_t iref = CTF_ERR, oref = CTF_ERR;
165
166	while (ctf_type_kind(ifp, iid) == CTF_K_TYPEDEF) {
167		iref = ctf_type_reference(ifp, iid);
168		if (iref == CTF_ERR)
169			return (CTF_ERR);
170		iid = iref;
171	}
172
173	while (ctf_type_kind(ofp, oid) == CTF_K_TYPEDEF) {
174		oref = ctf_type_reference(ofp, oid);
175		if (oref == CTF_ERR)
176			return (CTF_ERR);
177		oid = oref;
178	}
179
180	VERIFY(iref != CTF_ERR && oref != CTF_ERR);
181	return (ctf_diff_type(cds, ifp, iref, ofp, oref));
182}
183
184/*
185 * Two qualifiers are equivalent iff they point to two equivalent types.
186 */
187static int
188ctf_diff_qualifier(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid,
189    ctf_file_t *ofp, ctf_id_t oid)
190{
191	ctf_id_t iref, oref;
192
193	iref = ctf_type_reference(ifp, iid);
194	if (iref == CTF_ERR)
195		return (CTF_ERR);
196
197	oref = ctf_type_reference(ofp, oid);
198	if (oref == CTF_ERR)
199		return (ctf_set_errno(ifp, ctf_errno(ofp)));
200
201	return (ctf_diff_type(cds, ifp, iref, ofp, oref));
202}
203
204/*
205 * Two arrays are the same iff they have the same type for contents, the same
206 * type for the index, and the same number of elements.
207 */
208static int
209ctf_diff_array(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
210    ctf_id_t oid)
211{
212	int ret;
213	ctf_arinfo_t iar, oar;
214
215	if (ctf_array_info(ifp, iid, &iar) == CTF_ERR)
216		return (CTF_ERR);
217
218	if (ctf_array_info(ofp, oid, &oar) == CTF_ERR)
219		return (ctf_set_errno(ifp, ctf_errno(ofp)));
220
221	ret = ctf_diff_type(cds, ifp, iar.ctr_contents, ofp, oar.ctr_contents);
222	if (ret != B_FALSE)
223		return (ret);
224
225	if (iar.ctr_nelems != oar.ctr_nelems)
226		return (B_TRUE);
227
228	/*
229	 * If we're ignoring integer types names, then we're trying to do a bit
230	 * of a logical diff and we don't really care about the fact that the
231	 * index element might not be the same here, what we care about are the
232	 * number of elements and that they're the same type.
233	 */
234	if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0) {
235		ret = ctf_diff_type(cds, ifp, iar.ctr_index, ofp,
236		    oar.ctr_index);
237		if (ret != B_FALSE)
238			return (ret);
239	}
240
241	return (B_FALSE);
242}
243
244/*
245 * Two function pointers are the same if the following is all true:
246 *
247 *   o They have the same return type
248 *   o They have the same number of arguments
249 *   o The arguments are of the same type
250 *   o They have the same flags
251 */
252static int
253ctf_diff_fptr(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
254    ctf_id_t oid)
255{
256	int ret, i;
257	ctf_funcinfo_t ifunc, ofunc;
258	ctf_id_t *iids, *oids;
259
260	if (ctf_func_info_by_id(ifp, iid, &ifunc) == CTF_ERR)
261		return (CTF_ERR);
262
263	if (ctf_func_info_by_id(ofp, oid, &ofunc) == CTF_ERR)
264		return (ctf_set_errno(ifp, ctf_errno(ofp)));
265
266	if (ifunc.ctc_argc != ofunc.ctc_argc)
267		return (B_TRUE);
268
269	if (ifunc.ctc_flags != ofunc.ctc_flags)
270		return (B_TRUE);
271
272	ret = ctf_diff_type(cds, ifp, ifunc.ctc_return, ofp, ofunc.ctc_return);
273	if (ret != B_FALSE)
274		return (ret);
275
276	iids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc);
277	if (iids == NULL)
278		return (ctf_set_errno(ifp, ENOMEM));
279
280	oids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc);
281	if (oids == NULL) {
282		ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc);
283		return (ctf_set_errno(ifp, ENOMEM));
284	}
285
286	if (ctf_func_args_by_id(ifp, iid, ifunc.ctc_argc, iids) == CTF_ERR) {
287		ret = CTF_ERR;
288		goto out;
289	}
290
291	if (ctf_func_args_by_id(ofp, oid, ofunc.ctc_argc, oids) == CTF_ERR) {
292		ret = ctf_set_errno(ifp, ctf_errno(ofp));
293		goto out;
294	}
295
296	ret = B_TRUE;
297	for (i = 0; i < ifunc.ctc_argc; i++) {
298		ret = ctf_diff_type(cds, ifp, iids[i], ofp, oids[i]);
299		if (ret != B_FALSE)
300			goto out;
301	}
302	ret = B_FALSE;
303
304out:
305	ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc);
306	ctf_free(oids, sizeof (ctf_id_t) * ofunc.ctc_argc);
307	return (ret);
308}
309
310/*
311 * Two structures are the same if every member is identical to its corresponding
312 * type, at the same offset, and has the same name, as well as them having the
313 * same overall size.
314 */
315static int
316ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
317    ctf_id_t oid)
318{
319	ctf_file_t *oifp;
320	const ctf_type_t *itp, *otp;
321	ssize_t isize, iincr, osize, oincr;
322	const ctf_member_t *imp, *omp;
323	const ctf_lmember_t *ilmp, *olmp;
324	int n;
325	ctf_diff_guess_t *cdg;
326
327	oifp = ifp;
328
329	if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
330		return (CTF_ERR);
331
332	if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
333		return (ctf_set_errno(oifp, ctf_errno(ofp)));
334
335	if (ctf_type_size(ifp, iid) != ctf_type_size(ofp, oid))
336		return (B_TRUE);
337
338	if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
339	    LCTF_INFO_VLEN(ofp, otp->ctt_info))
340		return (B_TRUE);
341
342	(void) ctf_get_ctt_size(ifp, itp, &isize, &iincr);
343	(void) ctf_get_ctt_size(ofp, otp, &osize, &oincr);
344
345	if (ifp->ctf_version == CTF_VERSION_1 || isize < CTF_LSTRUCT_THRESH) {
346		imp = (const ctf_member_t *)((uintptr_t)itp + iincr);
347		ilmp = NULL;
348	} else {
349		imp = NULL;
350		ilmp = (const ctf_lmember_t *)((uintptr_t)itp + iincr);
351	}
352
353	if (ofp->ctf_version == CTF_VERSION_1 || osize < CTF_LSTRUCT_THRESH) {
354		omp = (const ctf_member_t *)((uintptr_t)otp + oincr);
355		olmp = NULL;
356	} else {
357		omp = NULL;
358		olmp = (const ctf_lmember_t *)((uintptr_t)otp + oincr);
359	}
360
361	/*
362	 * Insert our assumption that they're equal for the moment.
363	 */
364	cdg = ctf_alloc(sizeof (ctf_diff_guess_t));
365	if (cdg == NULL)
366		return (ctf_set_errno(ifp, ENOMEM));
367	cdg->cdg_iid = iid;
368	cdg->cdg_oid = oid;
369	cdg->cdg_next = cds->cds_guess;
370	cds->cds_guess = cdg;
371	cds->cds_forward[TINDEX(iid)] = oid;
372	cds->cds_reverse[TINDEX(oid)] = iid;
373
374	for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0; n--) {
375		const char *iname, *oname;
376		ulong_t ioff, ooff;
377		ctf_id_t itype, otype;
378		int ret;
379
380		if (imp != NULL) {
381			iname = ctf_strptr(ifp, imp->ctm_name);
382			ioff = imp->ctm_offset;
383			itype = imp->ctm_type;
384		} else {
385			iname = ctf_strptr(ifp, ilmp->ctlm_name);
386			ioff = CTF_LMEM_OFFSET(ilmp);
387			itype = ilmp->ctlm_type;
388		}
389
390		if (omp != NULL) {
391			oname = ctf_strptr(ofp, omp->ctm_name);
392			ooff = omp->ctm_offset;
393			otype = omp->ctm_type;
394		} else {
395			oname = ctf_strptr(ofp, olmp->ctlm_name);
396			ooff = CTF_LMEM_OFFSET(olmp);
397			otype = olmp->ctlm_type;
398		}
399
400		if (ioff != ooff) {
401			return (B_TRUE);
402		}
403		if (strcmp(iname, oname) != 0) {
404			return (B_TRUE);
405		}
406		ret = ctf_diff_type(cds, ifp, itype, ofp, otype);
407		if (ret != B_FALSE) {
408			return (ret);
409		}
410
411		/* Advance our pointers */
412		if (imp != NULL)
413			imp++;
414		if (ilmp != NULL)
415			ilmp++;
416		if (omp != NULL)
417			omp++;
418		if (olmp != NULL)
419			olmp++;
420	}
421
422	return (B_FALSE);
423}
424
425/*
426 * Two unions are the same if they have the same set of members. This is similar
427 * to, but slightly different from a struct. The offsets of members don't
428 * matter. However, there is no guarantee of ordering so we have to fall back to
429 * doing an O(N^2) scan.
430 */
431typedef struct ctf_diff_union_member {
432	ctf_diff_t *cdum_cds;
433	ctf_file_t *cdum_fp;
434	ctf_file_t *cdum_iterfp;
435	const char *cdum_name;
436	ctf_id_t cdum_type;
437	int cdum_ret;
438} ctf_diff_union_member_t;
439
440typedef struct ctf_diff_union_fp {
441	ctf_diff_t *cduf_cds;
442	ctf_file_t *cduf_curfp;
443	ctf_file_t *cduf_altfp;
444	ctf_id_t cduf_type;
445	int cduf_ret;
446} ctf_diff_union_fp_t;
447
448/* ARGSUSED */
449static int
450ctf_diff_union_check_member(const char *name, ctf_id_t id, ulong_t off,
451    void *arg)
452{
453	int ret;
454	ctf_diff_union_member_t *cdump = arg;
455
456	if (strcmp(name, cdump->cdum_name) != 0)
457		return (0);
458
459	ret = ctf_diff_type(cdump->cdum_cds, cdump->cdum_fp, cdump->cdum_type,
460	    cdump->cdum_iterfp, id);
461	if (ret == CTF_ERR) {
462		cdump->cdum_ret = CTF_ERR;
463		return (1);
464	}
465
466	if (ret == B_FALSE) {
467		cdump->cdum_ret = B_FALSE;
468		/* Return non-zero to stop iteration as we have a match */
469		return (1);
470	}
471
472	return (0);
473}
474
475/* ARGSUSED */
476static int
477ctf_diff_union_check_fp(const char *name, ctf_id_t id, ulong_t off, void *arg)
478{
479	int ret;
480	ctf_diff_union_member_t cdum;
481	ctf_diff_union_fp_t *cdufp = arg;
482
483	cdum.cdum_cds = cdufp->cduf_cds;
484	cdum.cdum_fp = cdufp->cduf_curfp;
485	cdum.cdum_iterfp = cdufp->cduf_altfp;
486	cdum.cdum_name = name;
487	cdum.cdum_type = id;
488	cdum.cdum_ret = B_TRUE;
489
490	ret = ctf_member_iter(cdum.cdum_iterfp, cdufp->cduf_type,
491	    ctf_diff_union_check_member, &cdum);
492	if (ret == 0 || cdum.cdum_ret == CTF_ERR) {
493		/* No match found or error, terminate now */
494		cdufp->cduf_ret = cdum.cdum_ret;
495		return (1);
496	} else if (ret == CTF_ERR) {
497		(void) ctf_set_errno(cdum.cdum_fp, ctf_errno(cdum.cdum_iterfp));
498		cdufp->cduf_ret = CTF_ERR;
499		return (1);
500	} else {
501		ASSERT(cdum.cdum_ret == B_FALSE);
502		cdufp->cduf_ret = cdum.cdum_ret;
503		return (0);
504	}
505}
506
507static int
508ctf_diff_union(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
509    ctf_id_t oid)
510{
511	ctf_file_t *oifp;
512	const ctf_type_t *itp, *otp;
513	ctf_diff_union_fp_t cduf;
514	ctf_diff_guess_t *cdg;
515	int ret;
516
517	oifp = ifp;
518	if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
519		return (CTF_ERR);
520	if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
521		return (ctf_set_errno(oifp, ctf_errno(ofp)));
522
523	if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
524	    LCTF_INFO_VLEN(ofp, otp->ctt_info))
525		return (B_TRUE);
526
527	cdg = ctf_alloc(sizeof (ctf_diff_guess_t));
528	if (cdg == NULL)
529		return (ctf_set_errno(ifp, ENOMEM));
530	cdg->cdg_iid = iid;
531	cdg->cdg_oid = oid;
532	cdg->cdg_next = cds->cds_guess;
533	cds->cds_guess = cdg;
534	cds->cds_forward[TINDEX(iid)] = oid;
535	cds->cds_reverse[TINDEX(oid)] = iid;
536
537	cduf.cduf_cds = cds;
538	cduf.cduf_curfp = ifp;
539	cduf.cduf_altfp = ofp;
540	cduf.cduf_type = oid;
541	cduf.cduf_ret = B_TRUE;
542	ret = ctf_member_iter(ifp, iid, ctf_diff_union_check_fp, &cduf);
543	if (ret != CTF_ERR)
544		ret = cduf.cduf_ret;
545
546	return (ret);
547}
548
549/*
550 * Two enums are equivalent if they share the same underlying type and they have
551 * the same set of members.
552 */
553static int
554ctf_diff_enum(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
555{
556	ctf_file_t *oifp;
557	const ctf_type_t *itp, *otp;
558	ssize_t iincr, oincr;
559	const ctf_enum_t *iep, *oep;
560	int n;
561
562	oifp = ifp;
563	if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL)
564		return (CTF_ERR);
565	if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
566		return (ctf_set_errno(oifp, ctf_errno(ofp)));
567
568	if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
569	    LCTF_INFO_VLEN(ofp, otp->ctt_info))
570		return (B_TRUE);
571
572	(void) ctf_get_ctt_size(ifp, itp, NULL, &iincr);
573	(void) ctf_get_ctt_size(ofp, otp, NULL, &oincr);
574	iep = (const ctf_enum_t *)((uintptr_t)itp + iincr);
575	oep = (const ctf_enum_t *)((uintptr_t)otp + oincr);
576
577	for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0;
578	    n--, iep++, oep++) {
579		if (strcmp(ctf_strptr(ifp, iep->cte_name),
580		    ctf_strptr(ofp, oep->cte_name)) != 0)
581			return (B_TRUE);
582
583		if (iep->cte_value != oep->cte_value)
584			return (B_TRUE);
585	}
586
587	return (B_FALSE);
588}
589
590/*
591 * Two forwards are equivalent in one of two cases. If both are forwards, than
592 * they are the same. Otherwise, they're equivalent if one is a struct or union
593 * and the other is a forward.
594 */
595static int
596ctf_diff_forward(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
597{
598	int ikind, okind;
599
600	ikind = ctf_type_kind(ifp, iid);
601	okind = ctf_type_kind(ofp, oid);
602
603	if (ikind == okind) {
604		ASSERT(ikind == CTF_K_FORWARD);
605		return (B_FALSE);
606	} else if (ikind == CTF_K_FORWARD) {
607		return (okind != CTF_K_UNION && okind != CTF_K_STRUCT);
608	} else {
609		return (ikind != CTF_K_UNION && ikind != CTF_K_STRUCT);
610	}
611}
612
613/*
614 * Are two types equivalent?
615 */
616int
617ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
618    ctf_id_t oid)
619{
620	int ret, ikind, okind;
621
622	/* Do a quick short circuit */
623	if (ifp == ofp && iid == oid)
624		return (B_FALSE);
625
626	/*
627	 * Check if it's something we've already encountered in a forward
628	 * reference or forward negative table. Also double check the reverse
629	 * table.
630	 */
631	if (cds->cds_forward[TINDEX(iid)] == oid)
632		return (B_FALSE);
633	if (cds->cds_forward[TINDEX(iid)] != 0)
634		return (B_TRUE);
635	if (cds->cds_reverse[TINDEX(oid)] == iid)
636		return (B_FALSE);
637	if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0 &&
638	    cds->cds_reverse[TINDEX(oid)] != 0)
639		return (B_TRUE);
640
641	ikind = ctf_type_kind(ifp, iid);
642	okind = ctf_type_kind(ofp, oid);
643
644	if (ikind != okind &&
645	    ikind != CTF_K_FORWARD && okind != CTF_K_FORWARD)
646			return (B_TRUE);
647
648	/* Check names */
649	if ((ret = ctf_diff_name(ifp, iid, ofp, oid)) != B_FALSE) {
650		if (ikind != okind || ikind != CTF_K_INTEGER ||
651		    (cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0)
652			return (ret);
653	}
654
655	if (ikind == CTF_K_FORWARD || okind == CTF_K_FORWARD)
656		return (ctf_diff_forward(ifp, iid, ofp, oid));
657
658	switch (ikind) {
659	case CTF_K_INTEGER:
660	case CTF_K_FLOAT:
661		ret = ctf_diff_number(ifp, iid, ofp, oid);
662		break;
663	case CTF_K_ARRAY:
664		ret = ctf_diff_array(cds, ifp, iid, ofp, oid);
665		break;
666	case CTF_K_FUNCTION:
667		ret = ctf_diff_fptr(cds, ifp, iid, ofp, oid);
668		break;
669	case CTF_K_STRUCT:
670		ret = ctf_diff_struct(cds, ifp, iid, ofp, oid);
671		break;
672	case CTF_K_UNION:
673		ret = ctf_diff_union(cds, ifp, iid, ofp, oid);
674		break;
675	case CTF_K_ENUM:
676		ret = ctf_diff_enum(ifp, iid, ofp, oid);
677		break;
678	case CTF_K_FORWARD:
679		ret = ctf_diff_forward(ifp, iid, ofp, oid);
680		break;
681	case CTF_K_TYPEDEF:
682		ret = ctf_diff_typedef(cds, ifp, iid, ofp, oid);
683		break;
684	case CTF_K_POINTER:
685	case CTF_K_VOLATILE:
686	case CTF_K_CONST:
687	case CTF_K_RESTRICT:
688		ret = ctf_diff_qualifier(cds, ifp, iid, ofp, oid);
689		break;
690	case CTF_K_UNKNOWN:
691		/*
692		 * The current CTF tools use CTF_K_UNKNOWN as a padding type. We
693		 * always declare two instances of CTF_K_UNKNOWN as different,
694		 * even though this leads to additional diff noise.
695		 */
696		ret = B_TRUE;
697		break;
698	default:
699		abort();
700	}
701
702	return (ret);
703}
704
705/*
706 * Walk every type in the first container and try to find a match in the second.
707 * If there is a match, then update both the forward and reverse mapping tables.
708 *
709 * The self variable tells us whether or not we should be comparing the input
710 * ctf container with itself or not.
711 */
712static int
713ctf_diff_pass1(ctf_diff_t *cds, boolean_t self)
714{
715	int i, j, diff;
716	int istart, iend, jstart, jend;
717
718	istart = 1;
719	iend = cds->cds_ifp->ctf_typemax;
720	if (cds->cds_ifp->ctf_flags & LCTF_CHILD) {
721		istart += CTF_CHILD_START;
722		iend += CTF_CHILD_START;
723	}
724
725	jstart = 1;
726	jend = cds->cds_ofp->ctf_typemax;
727	if (cds->cds_ofp->ctf_flags & LCTF_CHILD) {
728		jstart += CTF_CHILD_START;
729		jend += CTF_CHILD_START;
730	}
731
732	for (i = istart; i <= iend; i++) {
733		diff = B_TRUE;
734
735		/*
736		 * If we're doing a self diff for dedup purposes, then we want
737		 * to ensure that we compare a type i with every type in the
738		 * range, [ 1, i ). Yes, this does mean that when i equals 1,
739		 * we won't compare anything.
740		 */
741		if (self == B_TRUE) {
742			jstart = istart;
743			jend = i - 1;
744		}
745		for (j = jstart; j <= jend; j++) {
746			ctf_diff_guess_t *cdg, *tofree;
747
748			ASSERT(cds->cds_guess == NULL);
749			diff = ctf_diff_type(cds, cds->cds_ifp, i,
750			    cds->cds_ofp, j);
751			if (diff == CTF_ERR)
752				return (CTF_ERR);
753
754			/* Clean up our guesses */
755			cdg = cds->cds_guess;
756			cds->cds_guess = NULL;
757			while (cdg != NULL) {
758				if (diff == B_TRUE) {
759					cds->cds_forward[TINDEX(cdg->cdg_iid)] =
760					    0;
761					cds->cds_reverse[TINDEX(cdg->cdg_oid)] =
762					    0;
763				}
764				tofree = cdg;
765				cdg = cdg->cdg_next;
766				ctf_free(tofree, sizeof (ctf_diff_guess_t));
767			}
768
769			/* Found a hit, update the tables */
770			if (diff == B_FALSE) {
771				cds->cds_forward[TINDEX(i)] = j;
772				if (cds->cds_reverse[TINDEX(j)] == 0)
773					cds->cds_reverse[TINDEX(j)] = i;
774				break;
775			}
776		}
777
778		/* Call the callback at this point */
779		if (diff == B_TRUE) {
780			cds->cds_forward[TINDEX(i)] = CTF_ERR;
781			cds->cds_func(cds->cds_ifp, i, B_FALSE, NULL, CTF_ERR,
782			    cds->cds_arg);
783		} else {
784			cds->cds_func(cds->cds_ifp, i, B_TRUE, cds->cds_ofp, j,
785			    cds->cds_arg);
786		}
787	}
788
789	return (0);
790}
791
792/*
793 * Now we need to walk the second container and emit anything that we didn't
794 * find as common in the first pass.
795 */
796static int
797ctf_diff_pass2(ctf_diff_t *cds)
798{
799	int i, start, end;
800
801	start = 0x1;
802	end = cds->cds_ofp->ctf_typemax;
803	if (cds->cds_ofp->ctf_flags & LCTF_CHILD) {
804		start += CTF_CHILD_START;
805		end += CTF_CHILD_START;
806	}
807
808	for (i = start; i <= end; i++) {
809		if (cds->cds_reverse[TINDEX(i)] != 0)
810			continue;
811		cds->cds_func(cds->cds_ofp, i, B_FALSE, NULL, CTF_ERR,
812		    cds->cds_arg);
813	}
814
815	return (0);
816}
817
818int
819ctf_diff_init(ctf_file_t *ifp, ctf_file_t *ofp, ctf_diff_t **cdsp)
820{
821	ctf_diff_t *cds;
822	size_t fsize, rsize;
823
824	cds = ctf_alloc(sizeof (ctf_diff_t));
825	if (cds == NULL)
826		return (ctf_set_errno(ifp, ENOMEM));
827
828	bzero(cds, sizeof (ctf_diff_t));
829	cds->cds_ifp = ifp;
830	cds->cds_ofp = ofp;
831
832	fsize = sizeof (ctf_id_t) * ifp->ctf_typemax;
833	rsize = sizeof (ctf_id_t) * ofp->ctf_typemax;
834	if (ifp->ctf_flags & LCTF_CHILD)
835		fsize += CTF_CHILD_START * sizeof (ctf_id_t);
836	if (ofp->ctf_flags & LCTF_CHILD)
837		rsize += CTF_CHILD_START * sizeof (ctf_id_t);
838
839	cds->cds_forward = ctf_alloc(fsize);
840	if (cds->cds_forward == NULL) {
841		ctf_free(cds, sizeof (ctf_diff_t));
842		return (ctf_set_errno(ifp, ENOMEM));
843	}
844	cds->cds_fsize = fsize;
845	cds->cds_reverse = ctf_alloc(rsize);
846	if (cds->cds_reverse == NULL) {
847		ctf_free(cds->cds_forward, fsize);
848		ctf_free(cds, sizeof (ctf_diff_t));
849		return (ctf_set_errno(ifp, ENOMEM));
850	}
851	cds->cds_rsize = rsize;
852	bzero(cds->cds_forward, fsize);
853	bzero(cds->cds_reverse, rsize);
854
855	cds->cds_ifp->ctf_refcnt++;
856	cds->cds_ofp->ctf_refcnt++;
857	*cdsp = cds;
858	return (0);
859}
860
861int
862ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
863{
864	int ret;
865
866	cds->cds_func = cb;
867	cds->cds_arg = arg;
868
869	ret = ctf_diff_pass1(cds, B_FALSE);
870	if (ret == 0)
871		ret = ctf_diff_pass2(cds);
872
873	cds->cds_func = NULL;
874	cds->cds_arg = NULL;
875	cds->cds_tvalid = B_TRUE;
876	return (ret);
877}
878
879/*
880 * Do a diff where we're comparing a container with itself. In other words we'd
881 * like to know what types are actually duplicates of existing types in the
882 * container.
883 *
884 * Note this should remain private to libctf and not be exported in the public
885 * mapfile for the time being.
886 */
887int
888ctf_diff_self(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
889{
890	if (cds->cds_ifp != cds->cds_ofp)
891		return (EINVAL);
892
893	cds->cds_func = cb;
894	cds->cds_arg = arg;
895
896	return (ctf_diff_pass1(cds, B_TRUE));
897}
898
899
900void
901ctf_diff_fini(ctf_diff_t *cds)
902{
903	ctf_diff_guess_t *cdg;
904	size_t fsize, rsize;
905
906	if (cds == NULL)
907		return;
908
909	cds->cds_ifp->ctf_refcnt--;
910	cds->cds_ofp->ctf_refcnt--;
911
912	fsize = sizeof (ctf_id_t) * cds->cds_ifp->ctf_typemax;
913	rsize = sizeof (ctf_id_t) * cds->cds_ofp->ctf_typemax;
914	if (cds->cds_ifp->ctf_flags & LCTF_CHILD)
915		fsize += CTF_CHILD_START * sizeof (ctf_id_t);
916	if (cds->cds_ofp->ctf_flags & LCTF_CHILD)
917		rsize += CTF_CHILD_START * sizeof (ctf_id_t);
918
919	if (cds->cds_ifuncs != NULL)
920		ctf_free(cds->cds_ifuncs,
921		    sizeof (ctf_diff_func_t) * cds->cds_nifuncs);
922	if (cds->cds_ofuncs != NULL)
923		ctf_free(cds->cds_ofuncs,
924		    sizeof (ctf_diff_func_t) * cds->cds_nofuncs);
925	if (cds->cds_iobj != NULL)
926		ctf_free(cds->cds_iobj,
927		    sizeof (ctf_diff_obj_t) * cds->cds_niobj);
928	if (cds->cds_oobj != NULL)
929		ctf_free(cds->cds_oobj,
930		    sizeof (ctf_diff_obj_t) * cds->cds_noobj);
931	cdg = cds->cds_guess;
932	while (cdg != NULL) {
933		ctf_diff_guess_t *tofree = cdg;
934		cdg = cdg->cdg_next;
935		ctf_free(tofree, sizeof (ctf_diff_guess_t));
936	}
937	if (cds->cds_forward != NULL)
938		ctf_free(cds->cds_forward, cds->cds_fsize);
939	if (cds->cds_reverse != NULL)
940		ctf_free(cds->cds_reverse, cds->cds_rsize);
941	ctf_free(cds, sizeof (ctf_diff_t));
942}
943
944uint_t
945ctf_diff_getflags(ctf_diff_t *cds)
946{
947	return (cds->cds_flags);
948}
949
950int
951ctf_diff_setflags(ctf_diff_t *cds, uint_t flags)
952{
953	if ((flags & ~CTF_DIFF_F_IGNORE_INTNAMES) != 0)
954		return (ctf_set_errno(cds->cds_ifp, EINVAL));
955
956	cds->cds_flags = flags;
957	return (0);
958}
959
960static boolean_t
961ctf_diff_symid(ctf_diff_t *cds, ctf_id_t iid, ctf_id_t oid)
962{
963	ctf_file_t *ifp, *ofp;
964
965	ifp = cds->cds_ifp;
966	ofp = cds->cds_ofp;
967
968	/*
969	 * If we have parent containers on the scene here, we need to go through
970	 * and do a full diff check because a diff for types will not actually
971	 * go through and check types in the parent container.
972	 */
973	if (iid == 0 || oid == 0)
974		return (iid == oid ? B_FALSE: B_TRUE);
975
976	if (!(ifp->ctf_flags & LCTF_CHILD) && !(ofp->ctf_flags & LCTF_CHILD)) {
977		if (cds->cds_forward[TINDEX(iid)] != oid)
978			return (B_TRUE);
979		return (B_FALSE);
980	}
981
982	return (ctf_diff_type(cds, ifp, iid, ofp, oid));
983}
984
985/* ARGSUSED */
986static void
987ctf_diff_void_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
988    ctf_id_t oid, void *arg)
989{
990}
991
992/* ARGSUSED */
993static int
994ctf_diff_func_count(const char *name, ulong_t symidx, ctf_funcinfo_t *fip,
995    void *arg)
996{
997	uint32_t *ip = arg;
998
999	*ip = *ip + 1;
1000	return (0);
1001}
1002
1003/* ARGSUSED */
1004static int
1005ctf_diff_func_fill_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *fip,
1006    void *arg)
1007{
1008	uint_t *next, max;
1009	ctf_diff_func_t *funcptr;
1010	ctf_diff_t *cds = arg;
1011
1012	if (cds->cds_ffillip == B_TRUE) {
1013		max = cds->cds_nifuncs;
1014		next = &cds->cds_nextifunc;
1015		funcptr = cds->cds_ifuncs + *next;
1016	} else {
1017		max = cds->cds_nofuncs;
1018		next = &cds->cds_nextofunc;
1019		funcptr = cds->cds_ofuncs + *next;
1020
1021	}
1022
1023	VERIFY(*next < max);
1024	funcptr->cdf_name = name;
1025	funcptr->cdf_symidx = symidx;
1026	funcptr->cdf_matchidx = ULONG_MAX;
1027	*next = *next + 1;
1028
1029	return (0);
1030}
1031
1032int
1033ctf_diff_func_fill(ctf_diff_t *cds)
1034{
1035	int ret;
1036	uint32_t ifcount, ofcount, idcnt, cti;
1037	ulong_t i, j;
1038	ctf_id_t *iids, *oids;
1039
1040	ifcount = 0;
1041	ofcount = 0;
1042	idcnt = 0;
1043	iids = NULL;
1044	oids = NULL;
1045
1046	ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_count, &ifcount);
1047	if (ret != 0)
1048		return (ret);
1049	ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_count, &ofcount);
1050	if (ret != 0)
1051		return (ret);
1052
1053	cds->cds_ifuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ifcount);
1054	if (cds->cds_ifuncs == NULL)
1055		return (ctf_set_errno(cds->cds_ifp, ENOMEM));
1056
1057	cds->cds_nifuncs = ifcount;
1058	cds->cds_nextifunc = 0;
1059
1060	cds->cds_ofuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ofcount);
1061	if (cds->cds_ofuncs == NULL)
1062		return (ctf_set_errno(cds->cds_ifp, ENOMEM));
1063
1064	cds->cds_nofuncs = ofcount;
1065	cds->cds_nextofunc = 0;
1066
1067	cds->cds_ffillip = B_TRUE;
1068	if ((ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_fill_cb,
1069	    cds)) != 0)
1070		return (ret);
1071
1072	cds->cds_ffillip = B_FALSE;
1073	if ((ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_fill_cb,
1074	    cds)) != 0)
1075		return (ret);
1076
1077	/*
1078	 * Everything is initialized to not match. This could probably be faster
1079	 * with something that used a hash. But this part of the diff isn't used
1080	 * by merge.
1081	 */
1082	for (i = 0; i < cds->cds_nifuncs; i++) {
1083		for (j = 0; j < cds->cds_nofuncs; j++) {
1084			ctf_diff_func_t *ifd, *ofd;
1085			ctf_funcinfo_t ifip, ofip;
1086			boolean_t match;
1087
1088			ifd = &cds->cds_ifuncs[i];
1089			ofd = &cds->cds_ofuncs[j];
1090			if (strcmp(ifd->cdf_name, ofd->cdf_name) != 0)
1091				continue;
1092
1093			ret = ctf_func_info(cds->cds_ifp, ifd->cdf_symidx,
1094			    &ifip);
1095			if (ret != 0)
1096				goto out;
1097			ret = ctf_func_info(cds->cds_ofp, ofd->cdf_symidx,
1098			    &ofip);
1099			if (ret != 0) {
1100				ret = ctf_set_errno(cds->cds_ifp,
1101				    ctf_errno(cds->cds_ofp));
1102				goto out;
1103			}
1104
1105			if (ifip.ctc_argc != ofip.ctc_argc &&
1106			    ifip.ctc_flags != ofip.ctc_flags)
1107				continue;
1108
1109			/* Validate return type and arguments are the same */
1110			if (ctf_diff_symid(cds, ifip.ctc_return,
1111			    ofip.ctc_return))
1112				continue;
1113
1114			if (ifip.ctc_argc > idcnt) {
1115				if (iids != NULL)
1116					ctf_free(iids,
1117					    sizeof (ctf_id_t) * idcnt);
1118				if (oids != NULL)
1119					ctf_free(oids,
1120					    sizeof (ctf_id_t) * idcnt);
1121				iids = oids = NULL;
1122				idcnt = ifip.ctc_argc;
1123				iids = ctf_alloc(sizeof (ctf_id_t) * idcnt);
1124				if (iids == NULL) {
1125					ret = ctf_set_errno(cds->cds_ifp,
1126					    ENOMEM);
1127					goto out;
1128				}
1129				oids = ctf_alloc(sizeof (ctf_id_t) * idcnt);
1130				if (iids == NULL) {
1131					ret = ctf_set_errno(cds->cds_ifp,
1132					    ENOMEM);
1133					goto out;
1134				}
1135			}
1136
1137			if ((ret = ctf_func_args(cds->cds_ifp, ifd->cdf_symidx,
1138			    ifip.ctc_argc, iids)) != 0)
1139				goto out;
1140			if ((ret = ctf_func_args(cds->cds_ofp, ofd->cdf_symidx,
1141			    ofip.ctc_argc, oids)) != 0)
1142				goto out;
1143
1144			match = B_TRUE;
1145			for (cti = 0; cti < ifip.ctc_argc; cti++) {
1146				if (ctf_diff_symid(cds, iids[cti], oids[cti])) {
1147					match = B_FALSE;
1148					break;
1149				}
1150			}
1151
1152			if (match == B_FALSE)
1153				continue;
1154
1155			ifd->cdf_matchidx = j;
1156			ofd->cdf_matchidx = i;
1157			break;
1158		}
1159	}
1160
1161	ret = 0;
1162
1163out:
1164	if (iids != NULL)
1165		ctf_free(iids, sizeof (ctf_id_t) * idcnt);
1166	if (oids != NULL)
1167		ctf_free(oids, sizeof (ctf_id_t) * idcnt);
1168
1169	return (ret);
1170}
1171
1172/*
1173 * In general, two functions are the same, if they have the same name and their
1174 * arguments have the same types, including the return type. Like types, we
1175 * basically have to do this in two passes. In the first phase we walk every
1176 * type in the first container and try to find a match in the second.
1177 */
1178int
1179ctf_diff_functions(ctf_diff_t *cds, ctf_diff_func_f cb, void *arg)
1180{
1181	int ret;
1182	ulong_t i;
1183
1184	if (cds->cds_tvalid == B_FALSE) {
1185		if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0)
1186			return (ret);
1187	}
1188
1189	if (cds->cds_fvalid == B_FALSE) {
1190		if ((ret = ctf_diff_func_fill(cds)) != 0)
1191			return (ret);
1192		cds->cds_fvalid = B_TRUE;
1193	}
1194
1195	for (i = 0; i < cds->cds_nifuncs; i++) {
1196		if (cds->cds_ifuncs[i].cdf_matchidx == ULONG_MAX) {
1197			cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx,
1198			    B_FALSE, NULL, ULONG_MAX, arg);
1199		} else {
1200			ulong_t idx = cds->cds_ifuncs[i].cdf_matchidx;
1201			cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx, B_TRUE,
1202			    cds->cds_ofp, cds->cds_ofuncs[idx].cdf_symidx, arg);
1203		}
1204	}
1205
1206	for (i = 0; i < cds->cds_nofuncs; i++) {
1207		if (cds->cds_ofuncs[i].cdf_matchidx != ULONG_MAX)
1208			continue;
1209		cb(cds->cds_ofp, cds->cds_ofuncs[i].cdf_symidx, B_FALSE,
1210		    NULL, ULONG_MAX, arg);
1211	}
1212
1213	return (0);
1214}
1215
1216static int
1217ctf_diff_obj_fill_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
1218{
1219	uint_t *next, max;
1220	ctf_diff_obj_t *objptr;
1221	ctf_diff_t *cds = arg;
1222
1223	if (cds->cds_ofillip == B_TRUE) {
1224		max = cds->cds_niobj;
1225		next = &cds->cds_nextiobj;
1226		objptr = cds->cds_iobj + *next;
1227	} else {
1228		max = cds->cds_noobj;
1229		next = &cds->cds_nextoobj;
1230		objptr = cds->cds_oobj+ *next;
1231
1232	}
1233
1234	VERIFY(*next < max);
1235	objptr->cdo_name = name;
1236	objptr->cdo_symidx = symidx;
1237	objptr->cdo_id = id;
1238	objptr->cdo_matchidx = ULONG_MAX;
1239	*next = *next + 1;
1240
1241	return (0);
1242}
1243
1244/* ARGSUSED */
1245static int
1246ctf_diff_obj_count(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
1247{
1248	uint32_t *count = arg;
1249
1250	*count = *count + 1;
1251
1252	return (0);
1253}
1254
1255
1256static int
1257ctf_diff_obj_fill(ctf_diff_t *cds)
1258{
1259	int ret;
1260	uint32_t iocount, oocount;
1261	ulong_t i, j;
1262
1263	iocount = 0;
1264	oocount = 0;
1265
1266	ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_count, &iocount);
1267	if (ret != 0)
1268		return (ret);
1269
1270	ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_count, &oocount);
1271	if (ret != 0)
1272		return (ret);
1273
1274	cds->cds_iobj = ctf_alloc(sizeof (ctf_diff_obj_t) * iocount);
1275	if (cds->cds_iobj == NULL)
1276		return (ctf_set_errno(cds->cds_ifp, ENOMEM));
1277	cds->cds_niobj = iocount;
1278	cds->cds_nextiobj = 0;
1279
1280	cds->cds_oobj = ctf_alloc(sizeof (ctf_diff_obj_t) * oocount);
1281	if (cds->cds_oobj == NULL)
1282		return (ctf_set_errno(cds->cds_ifp, ENOMEM));
1283	cds->cds_noobj = oocount;
1284	cds->cds_nextoobj = 0;
1285
1286	cds->cds_ofillip = B_TRUE;
1287	if ((ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_fill_cb,
1288	    cds)) != 0)
1289		return (ret);
1290
1291	cds->cds_ofillip = B_FALSE;
1292	if ((ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_fill_cb,
1293	    cds)) != 0)
1294		return (ret);
1295
1296	for (i = 0; i < cds->cds_niobj; i++) {
1297		for (j = 0; j < cds->cds_noobj; j++) {
1298			ctf_diff_obj_t *id, *od;
1299
1300			id = &cds->cds_iobj[i];
1301			od = &cds->cds_oobj[j];
1302
1303			if (id->cdo_name == NULL || od->cdo_name == NULL)
1304				continue;
1305			if (strcmp(id->cdo_name, od->cdo_name) != 0)
1306				continue;
1307
1308			if (ctf_diff_symid(cds, id->cdo_id, od->cdo_id)) {
1309				continue;
1310			}
1311
1312			id->cdo_matchidx = j;
1313			od->cdo_matchidx = i;
1314			break;
1315		}
1316	}
1317
1318	return (0);
1319}
1320
1321int
1322ctf_diff_objects(ctf_diff_t *cds, ctf_diff_obj_f cb, void *arg)
1323{
1324	int ret;
1325	ulong_t i;
1326
1327	if (cds->cds_tvalid == B_FALSE) {
1328		if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0)
1329			return (ret);
1330	}
1331
1332	if (cds->cds_ovalid == B_FALSE) {
1333		if ((ret = ctf_diff_obj_fill(cds)) != 0)
1334			return (ret);
1335		cds->cds_ovalid = B_TRUE;
1336	}
1337
1338	for (i = 0; i < cds->cds_niobj; i++) {
1339		ctf_diff_obj_t *o = &cds->cds_iobj[i];
1340
1341		if (cds->cds_iobj[i].cdo_matchidx == ULONG_MAX) {
1342			cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_FALSE,
1343			    NULL, ULONG_MAX, CTF_ERR, arg);
1344		} else {
1345			ctf_diff_obj_t *alt = &cds->cds_oobj[o->cdo_matchidx];
1346			cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_TRUE,
1347			    cds->cds_ofp, alt->cdo_symidx, alt->cdo_id, arg);
1348		}
1349	}
1350
1351	for (i = 0; i < cds->cds_noobj; i++) {
1352		ctf_diff_obj_t *o = &cds->cds_oobj[i];
1353		if (o->cdo_matchidx != ULONG_MAX)
1354			continue;
1355		cb(cds->cds_ofp, o->cdo_symidx, o->cdo_id, B_FALSE, NULL,
1356		    ULONG_MAX, CTF_ERR, arg);
1357	}
1358
1359	return (0);
1360}
1361