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