xref: /illumos-gate/usr/src/cmd/ctfdiff/ctfdiff.c (revision bc1f688b)
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.
14*bc1f688bSRobert Mustacchi  */
15*bc1f688bSRobert Mustacchi 
16*bc1f688bSRobert Mustacchi /*
17*bc1f688bSRobert Mustacchi  * diff two CTF containers
18*bc1f688bSRobert Mustacchi  */
19*bc1f688bSRobert Mustacchi 
20*bc1f688bSRobert Mustacchi #include <stdio.h>
21*bc1f688bSRobert Mustacchi #include <stdlib.h>
22*bc1f688bSRobert Mustacchi #include <errno.h>
23*bc1f688bSRobert Mustacchi #include <strings.h>
24*bc1f688bSRobert Mustacchi #include <libctf.h>
25*bc1f688bSRobert Mustacchi #include <libgen.h>
26*bc1f688bSRobert Mustacchi #include <stdarg.h>
27*bc1f688bSRobert Mustacchi 
28*bc1f688bSRobert Mustacchi #define	CTFDIFF_NAMELEN	256
29*bc1f688bSRobert Mustacchi 
30*bc1f688bSRobert Mustacchi #define	CTFDIFF_EXIT_SIMILAR	0
31*bc1f688bSRobert Mustacchi #define	CTFDIFF_EXIT_DIFFERENT	1
32*bc1f688bSRobert Mustacchi #define	CTFDIFF_EXIT_USAGE	2
33*bc1f688bSRobert Mustacchi #define	CTFDIFF_EXIT_ERROR	3
34*bc1f688bSRobert Mustacchi 
35*bc1f688bSRobert Mustacchi typedef enum ctf_diff_cmd {
36*bc1f688bSRobert Mustacchi 	CTF_DIFF_TYPES =	0x01,
37*bc1f688bSRobert Mustacchi 	CTF_DIFF_FUNCS =	0x02,
38*bc1f688bSRobert Mustacchi 	CTF_DIFF_OBJS =		0x04,
39*bc1f688bSRobert Mustacchi 	CTF_DIFF_DEFAULT =	0x07,
40*bc1f688bSRobert Mustacchi 	CTF_DIFF_LABEL =	0x08,
41*bc1f688bSRobert Mustacchi 	CTF_DIFF_ALL =		0x0f
42*bc1f688bSRobert Mustacchi } ctf_diff_cmd_t;
43*bc1f688bSRobert Mustacchi 
44*bc1f688bSRobert Mustacchi typedef struct {
45*bc1f688bSRobert Mustacchi 	int		dil_next;
46*bc1f688bSRobert Mustacchi 	const char	**dil_labels;
47*bc1f688bSRobert Mustacchi } ctfdiff_label_t;
48*bc1f688bSRobert Mustacchi 
49*bc1f688bSRobert Mustacchi static char *g_progname;
50*bc1f688bSRobert Mustacchi static const char *g_iname;
51*bc1f688bSRobert Mustacchi static ctf_file_t *g_ifp;
52*bc1f688bSRobert Mustacchi static const char *g_oname;
53*bc1f688bSRobert Mustacchi static ctf_file_t *g_ofp;
54*bc1f688bSRobert Mustacchi static char **g_typelist = NULL;
55*bc1f688bSRobert Mustacchi static int g_nexttype = 0;
56*bc1f688bSRobert Mustacchi static int g_ntypes = 0;
57*bc1f688bSRobert Mustacchi static char **g_objlist = NULL;
58*bc1f688bSRobert Mustacchi static int g_nextfunc = 0;
59*bc1f688bSRobert Mustacchi static int g_nfuncs = 0;
60*bc1f688bSRobert Mustacchi static char **g_funclist = NULL;
61*bc1f688bSRobert Mustacchi static int g_nextobj = 0;
62*bc1f688bSRobert Mustacchi static int g_nobjs = 0;
63*bc1f688bSRobert Mustacchi static boolean_t g_onlydiff = B_FALSE;
64*bc1f688bSRobert Mustacchi static boolean_t g_different = B_FALSE;
65*bc1f688bSRobert Mustacchi static ctf_diff_cmd_t g_flag = 0;
66*bc1f688bSRobert Mustacchi 
67*bc1f688bSRobert Mustacchi static void
ctfdiff_fatal(const char * fmt,...)68*bc1f688bSRobert Mustacchi ctfdiff_fatal(const char *fmt, ...)
69*bc1f688bSRobert Mustacchi {
70*bc1f688bSRobert Mustacchi 	va_list ap;
71*bc1f688bSRobert Mustacchi 
72*bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "%s: ", g_progname);
73*bc1f688bSRobert Mustacchi 	va_start(ap, fmt);
74*bc1f688bSRobert Mustacchi 	(void) vfprintf(stderr, fmt, ap);
75*bc1f688bSRobert Mustacchi 	va_end(ap);
76*bc1f688bSRobert Mustacchi 
77*bc1f688bSRobert Mustacchi 	exit(CTFDIFF_EXIT_ERROR);
78*bc1f688bSRobert Mustacchi }
79*bc1f688bSRobert Mustacchi 
80*bc1f688bSRobert Mustacchi static const char *
ctfdiff_fp_to_name(ctf_file_t * fp)81*bc1f688bSRobert Mustacchi ctfdiff_fp_to_name(ctf_file_t *fp)
82*bc1f688bSRobert Mustacchi {
83*bc1f688bSRobert Mustacchi 	if (fp == g_ifp)
84*bc1f688bSRobert Mustacchi 		return (g_iname);
85*bc1f688bSRobert Mustacchi 	if (fp == g_ofp)
86*bc1f688bSRobert Mustacchi 		return (g_oname);
87*bc1f688bSRobert Mustacchi 	return (NULL);
88*bc1f688bSRobert Mustacchi }
89*bc1f688bSRobert Mustacchi 
90*bc1f688bSRobert Mustacchi /* ARGSUSED */
91*bc1f688bSRobert Mustacchi static void
ctfdiff_func_cb(ctf_file_t * ifp,ulong_t iidx,boolean_t similar,ctf_file_t * ofp,ulong_t oidx,void * arg)92*bc1f688bSRobert Mustacchi ctfdiff_func_cb(ctf_file_t *ifp, ulong_t iidx, boolean_t similar,
93*bc1f688bSRobert Mustacchi     ctf_file_t *ofp, ulong_t oidx, void *arg)
94*bc1f688bSRobert Mustacchi {
95*bc1f688bSRobert Mustacchi 	char namebuf[CTFDIFF_NAMELEN];
96*bc1f688bSRobert Mustacchi 
97*bc1f688bSRobert Mustacchi 	if (similar == B_TRUE)
98*bc1f688bSRobert Mustacchi 		return;
99*bc1f688bSRobert Mustacchi 
100*bc1f688bSRobert Mustacchi 	if (ctf_symbol_name(ifp, iidx, namebuf, sizeof (namebuf)) == NULL) {
101*bc1f688bSRobert Mustacchi 		if (g_nextfunc != 0)
102*bc1f688bSRobert Mustacchi 			return;
103*bc1f688bSRobert Mustacchi 		(void) printf("ctf container %s function %lu is different\n",
104*bc1f688bSRobert Mustacchi 		    ctfdiff_fp_to_name(ifp), iidx);
105*bc1f688bSRobert Mustacchi 	} else {
106*bc1f688bSRobert Mustacchi 		if (g_nextfunc != 0) {
107*bc1f688bSRobert Mustacchi 			int i;
108*bc1f688bSRobert Mustacchi 			for (i = 0; i < g_nextfunc; i++) {
109*bc1f688bSRobert Mustacchi 				if (strcmp(g_funclist[i], namebuf) == 0)
110*bc1f688bSRobert Mustacchi 					break;
111*bc1f688bSRobert Mustacchi 			}
112*bc1f688bSRobert Mustacchi 			if (i == g_nextfunc)
113*bc1f688bSRobert Mustacchi 				return;
114*bc1f688bSRobert Mustacchi 		}
115*bc1f688bSRobert Mustacchi 		(void) printf("ctf container %s function %s (%lu) is "
116*bc1f688bSRobert Mustacchi 		    "different\n", ctfdiff_fp_to_name(ifp), namebuf, iidx);
117*bc1f688bSRobert Mustacchi 	}
118*bc1f688bSRobert Mustacchi 
119*bc1f688bSRobert Mustacchi 	g_different = B_TRUE;
120*bc1f688bSRobert Mustacchi }
121*bc1f688bSRobert Mustacchi 
122*bc1f688bSRobert Mustacchi /* ARGSUSED */
123*bc1f688bSRobert Mustacchi static void
ctfdiff_obj_cb(ctf_file_t * ifp,ulong_t iidx,ctf_id_t iid,boolean_t similar,ctf_file_t * ofp,ulong_t oidx,ctf_id_t oid,void * arg)124*bc1f688bSRobert Mustacchi ctfdiff_obj_cb(ctf_file_t *ifp, ulong_t iidx, ctf_id_t iid, boolean_t similar,
125*bc1f688bSRobert Mustacchi     ctf_file_t *ofp, ulong_t oidx, ctf_id_t oid, void *arg)
126*bc1f688bSRobert Mustacchi {
127*bc1f688bSRobert Mustacchi 	char namebuf[CTFDIFF_NAMELEN];
128*bc1f688bSRobert Mustacchi 
129*bc1f688bSRobert Mustacchi 	if (similar == B_TRUE)
130*bc1f688bSRobert Mustacchi 		return;
131*bc1f688bSRobert Mustacchi 
132*bc1f688bSRobert Mustacchi 	if (ctf_symbol_name(ifp, iidx, namebuf, sizeof (namebuf)) == NULL) {
133*bc1f688bSRobert Mustacchi 		if (g_nextobj != 0)
134*bc1f688bSRobert Mustacchi 			return;
135*bc1f688bSRobert Mustacchi 		(void) printf("ctf container %s object %lu is different\n",
136*bc1f688bSRobert Mustacchi 		    ctfdiff_fp_to_name(ifp), iidx);
137*bc1f688bSRobert Mustacchi 	} else {
138*bc1f688bSRobert Mustacchi 		if (g_nextobj != 0) {
139*bc1f688bSRobert Mustacchi 			int i;
140*bc1f688bSRobert Mustacchi 			for (i = 0; i < g_nextobj; i++) {
141*bc1f688bSRobert Mustacchi 				if (strcmp(g_objlist[i], namebuf) == 0)
142*bc1f688bSRobert Mustacchi 					break;
143*bc1f688bSRobert Mustacchi 			}
144*bc1f688bSRobert Mustacchi 			if (i == g_nextobj)
145*bc1f688bSRobert Mustacchi 				return;
146*bc1f688bSRobert Mustacchi 		}
147*bc1f688bSRobert Mustacchi 		(void) printf("ctf container %s object %s (%lu) is different\n",
148*bc1f688bSRobert Mustacchi 		    ctfdiff_fp_to_name(ifp), namebuf, iidx);
149*bc1f688bSRobert Mustacchi 	}
150*bc1f688bSRobert Mustacchi 
151*bc1f688bSRobert Mustacchi 	g_different = B_TRUE;
152*bc1f688bSRobert Mustacchi }
153*bc1f688bSRobert Mustacchi 
154*bc1f688bSRobert Mustacchi /* ARGSUSED */
155*bc1f688bSRobert Mustacchi static void
ctfdiff_cb(ctf_file_t * ifp,ctf_id_t iid,boolean_t similar,ctf_file_t * ofp,ctf_id_t oid,void * arg)156*bc1f688bSRobert Mustacchi ctfdiff_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t similar, ctf_file_t *ofp,
157*bc1f688bSRobert Mustacchi     ctf_id_t oid, void *arg)
158*bc1f688bSRobert Mustacchi {
159*bc1f688bSRobert Mustacchi 	if (similar == B_TRUE)
160*bc1f688bSRobert Mustacchi 		return;
161*bc1f688bSRobert Mustacchi 
162*bc1f688bSRobert Mustacchi 	if (ctf_type_kind(ifp, iid) == CTF_K_UNKNOWN)
163*bc1f688bSRobert Mustacchi 		return;
164*bc1f688bSRobert Mustacchi 
165*bc1f688bSRobert Mustacchi 	/*
166*bc1f688bSRobert Mustacchi 	 * Check if it's the type the user cares about.
167*bc1f688bSRobert Mustacchi 	 */
168*bc1f688bSRobert Mustacchi 	if (g_nexttype != 0) {
169*bc1f688bSRobert Mustacchi 		int i;
170*bc1f688bSRobert Mustacchi 		char namebuf[CTFDIFF_NAMELEN];
171*bc1f688bSRobert Mustacchi 
172*bc1f688bSRobert Mustacchi 		if (ctf_type_name(ifp, iid, namebuf, sizeof (namebuf)) ==
173*bc1f688bSRobert Mustacchi 		    NULL) {
174*bc1f688bSRobert Mustacchi 			ctfdiff_fatal("failed to obtain the name "
175*bc1f688bSRobert Mustacchi 			    "of type %ld from %s: %s\n",
176*bc1f688bSRobert Mustacchi 			    iid, ctfdiff_fp_to_name(ifp),
177*bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(ifp)));
178*bc1f688bSRobert Mustacchi 		}
179*bc1f688bSRobert Mustacchi 
180*bc1f688bSRobert Mustacchi 		for (i = 0; i < g_nexttype; i++) {
181*bc1f688bSRobert Mustacchi 			if (strcmp(g_typelist[i], namebuf) == 0)
182*bc1f688bSRobert Mustacchi 				break;
183*bc1f688bSRobert Mustacchi 		}
184*bc1f688bSRobert Mustacchi 
185*bc1f688bSRobert Mustacchi 		if (i == g_nexttype)
186*bc1f688bSRobert Mustacchi 			return;
187*bc1f688bSRobert Mustacchi 	}
188*bc1f688bSRobert Mustacchi 
189*bc1f688bSRobert Mustacchi 	g_different = B_TRUE;
190*bc1f688bSRobert Mustacchi 
191*bc1f688bSRobert Mustacchi 	if (g_onlydiff == B_TRUE)
192*bc1f688bSRobert Mustacchi 		return;
193*bc1f688bSRobert Mustacchi 
194*bc1f688bSRobert Mustacchi 	(void) printf("ctf container %s type %ld is different\n",
195*bc1f688bSRobert Mustacchi 	    ctfdiff_fp_to_name(ifp), iid);
196*bc1f688bSRobert Mustacchi }
197*bc1f688bSRobert Mustacchi 
198*bc1f688bSRobert Mustacchi /* ARGSUSED */
199*bc1f688bSRobert Mustacchi static int
ctfdiff_labels_count(const char * name,const ctf_lblinfo_t * li,void * arg)200*bc1f688bSRobert Mustacchi ctfdiff_labels_count(const char *name, const ctf_lblinfo_t *li, void *arg)
201*bc1f688bSRobert Mustacchi {
202*bc1f688bSRobert Mustacchi 	uint32_t *count = arg;
203*bc1f688bSRobert Mustacchi 	*count = *count + 1;
204*bc1f688bSRobert Mustacchi 
205*bc1f688bSRobert Mustacchi 	return (0);
206*bc1f688bSRobert Mustacchi }
207*bc1f688bSRobert Mustacchi 
208*bc1f688bSRobert Mustacchi /* ARGSUSED */
209*bc1f688bSRobert Mustacchi static int
ctfdiff_labels_fill(const char * name,const ctf_lblinfo_t * li,void * arg)210*bc1f688bSRobert Mustacchi ctfdiff_labels_fill(const char *name, const ctf_lblinfo_t *li, void *arg)
211*bc1f688bSRobert Mustacchi {
212*bc1f688bSRobert Mustacchi 	ctfdiff_label_t *dil = arg;
213*bc1f688bSRobert Mustacchi 
214*bc1f688bSRobert Mustacchi 	dil->dil_labels[dil->dil_next] = name;
215*bc1f688bSRobert Mustacchi 	dil->dil_next++;
216*bc1f688bSRobert Mustacchi 
217*bc1f688bSRobert Mustacchi 	return (0);
218*bc1f688bSRobert Mustacchi }
219*bc1f688bSRobert Mustacchi 
220*bc1f688bSRobert Mustacchi static int
ctfdiff_labels(ctf_file_t * ifp,ctf_file_t * ofp)221*bc1f688bSRobert Mustacchi ctfdiff_labels(ctf_file_t *ifp, ctf_file_t *ofp)
222*bc1f688bSRobert Mustacchi {
223*bc1f688bSRobert Mustacchi 	int ret;
224*bc1f688bSRobert Mustacchi 	uint32_t nilabel, nolabel, i, j;
225*bc1f688bSRobert Mustacchi 	ctfdiff_label_t idl, odl;
226*bc1f688bSRobert Mustacchi 	const char **ilptr, **olptr;
227*bc1f688bSRobert Mustacchi 
228*bc1f688bSRobert Mustacchi 	nilabel = nolabel = 0;
229*bc1f688bSRobert Mustacchi 	ret = ctf_label_iter(ifp, ctfdiff_labels_count, &nilabel);
230*bc1f688bSRobert Mustacchi 	if (ret == CTF_ERR)
231*bc1f688bSRobert Mustacchi 		return (ret);
232*bc1f688bSRobert Mustacchi 	ret = ctf_label_iter(ofp, ctfdiff_labels_count, &nolabel);
233*bc1f688bSRobert Mustacchi 	if (ret == CTF_ERR)
234*bc1f688bSRobert Mustacchi 		return (ret);
235*bc1f688bSRobert Mustacchi 
236*bc1f688bSRobert Mustacchi 	if (nilabel != nolabel) {
237*bc1f688bSRobert Mustacchi 		(void) printf("ctf container %s labels differ from ctf "
238*bc1f688bSRobert Mustacchi 		    "container %s\n", ctfdiff_fp_to_name(ifp),
239*bc1f688bSRobert Mustacchi 		    ctfdiff_fp_to_name(ofp));
240*bc1f688bSRobert Mustacchi 		g_different = B_TRUE;
241*bc1f688bSRobert Mustacchi 		return (0);
242*bc1f688bSRobert Mustacchi 	}
243*bc1f688bSRobert Mustacchi 
244*bc1f688bSRobert Mustacchi 	if (nilabel == 0)
245*bc1f688bSRobert Mustacchi 		return (0);
246*bc1f688bSRobert Mustacchi 
247*bc1f688bSRobert Mustacchi 	ilptr = malloc(sizeof (char *) * nilabel);
248*bc1f688bSRobert Mustacchi 	olptr = malloc(sizeof (char *) * nolabel);
249*bc1f688bSRobert Mustacchi 	if (ilptr == NULL || olptr == NULL) {
250*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("failed to allocate memory for label "
251*bc1f688bSRobert Mustacchi 		    "comparison\n");
252*bc1f688bSRobert Mustacchi 	}
253*bc1f688bSRobert Mustacchi 
254*bc1f688bSRobert Mustacchi 	idl.dil_next = 0;
255*bc1f688bSRobert Mustacchi 	idl.dil_labels = ilptr;
256*bc1f688bSRobert Mustacchi 	odl.dil_next = 0;
257*bc1f688bSRobert Mustacchi 	odl.dil_labels = olptr;
258*bc1f688bSRobert Mustacchi 
259*bc1f688bSRobert Mustacchi 	if ((ret = ctf_label_iter(ifp, ctfdiff_labels_fill, &idl)) != 0)
260*bc1f688bSRobert Mustacchi 		goto out;
261*bc1f688bSRobert Mustacchi 	if ((ret = ctf_label_iter(ofp, ctfdiff_labels_fill, &odl)) != 0)
262*bc1f688bSRobert Mustacchi 		goto out;
263*bc1f688bSRobert Mustacchi 
264*bc1f688bSRobert Mustacchi 	for (i = 0; i < nilabel; i++) {
265*bc1f688bSRobert Mustacchi 		for (j = 0; j < nolabel; j++) {
266*bc1f688bSRobert Mustacchi 			if (strcmp(ilptr[i], olptr[j]) == 0)
267*bc1f688bSRobert Mustacchi 				break;
268*bc1f688bSRobert Mustacchi 		}
269*bc1f688bSRobert Mustacchi 
270*bc1f688bSRobert Mustacchi 		if (j == nolabel) {
271*bc1f688bSRobert Mustacchi 			(void) printf("ctf container %s labels differ from ctf "
272*bc1f688bSRobert Mustacchi 			    "container %s\n", ctfdiff_fp_to_name(ifp),
273*bc1f688bSRobert Mustacchi 			    ctfdiff_fp_to_name(ofp));
274*bc1f688bSRobert Mustacchi 			g_different = B_TRUE;
275*bc1f688bSRobert Mustacchi 			break;
276*bc1f688bSRobert Mustacchi 		}
277*bc1f688bSRobert Mustacchi 	}
278*bc1f688bSRobert Mustacchi 
279*bc1f688bSRobert Mustacchi 	ret = 0;
280*bc1f688bSRobert Mustacchi out:
281*bc1f688bSRobert Mustacchi 	free(ilptr);
282*bc1f688bSRobert Mustacchi 	free(olptr);
283*bc1f688bSRobert Mustacchi 	return (ret);
284*bc1f688bSRobert Mustacchi }
285*bc1f688bSRobert Mustacchi 
286*bc1f688bSRobert Mustacchi static void
ctfdiff_usage(const char * fmt,...)287*bc1f688bSRobert Mustacchi ctfdiff_usage(const char *fmt, ...)
288*bc1f688bSRobert Mustacchi {
289*bc1f688bSRobert Mustacchi 	if (fmt != NULL) {
290*bc1f688bSRobert Mustacchi 		va_list ap;
291*bc1f688bSRobert Mustacchi 
292*bc1f688bSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", g_progname);
293*bc1f688bSRobert Mustacchi 		va_start(ap, fmt);
294*bc1f688bSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
295*bc1f688bSRobert Mustacchi 		va_end(ap);
296*bc1f688bSRobert Mustacchi 	}
297*bc1f688bSRobert Mustacchi 
298*bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s [-afIloqt] [-F function] [-O object]"
299*bc1f688bSRobert Mustacchi 	    "[-p parent] [-P parent]\n"
300*bc1f688bSRobert Mustacchi 	    "\t[-T type] file1 file2\n"
301*bc1f688bSRobert Mustacchi 	    "\n"
302*bc1f688bSRobert Mustacchi 	    "\t-a diff label, types, objects, and functions\n"
303*bc1f688bSRobert Mustacchi 	    "\t-f diff function type information\n"
304*bc1f688bSRobert Mustacchi 	    "\t-F when diffing functions, only consider those named\n"
305*bc1f688bSRobert Mustacchi 	    "\t-I ignore the names of integral types\n"
306*bc1f688bSRobert Mustacchi 	    "\t-l diff CTF labels\n"
307*bc1f688bSRobert Mustacchi 	    "\t-o diff global object type information\n"
308*bc1f688bSRobert Mustacchi 	    "\t-O when diffing objects, only consider those named\n"
309*bc1f688bSRobert Mustacchi 	    "\t-p set the CTF parent for file1\n"
310*bc1f688bSRobert Mustacchi 	    "\t-P set the CTF parent for file2\n"
311*bc1f688bSRobert Mustacchi 	    "\t-q set quiet mode (no diff information sent to stdout)\n"
312*bc1f688bSRobert Mustacchi 	    "\t-t diff CTF type information\n"
313*bc1f688bSRobert Mustacchi 	    "\t-T when diffing types, only consider those named\n",
314*bc1f688bSRobert Mustacchi 	    g_progname);
315*bc1f688bSRobert Mustacchi }
316*bc1f688bSRobert Mustacchi 
317*bc1f688bSRobert Mustacchi int
main(int argc,char * argv[])318*bc1f688bSRobert Mustacchi main(int argc, char *argv[])
319*bc1f688bSRobert Mustacchi {
320*bc1f688bSRobert Mustacchi 	ctf_diff_flag_t flags = 0;
321*bc1f688bSRobert Mustacchi 	int err, c;
322*bc1f688bSRobert Mustacchi 	ctf_file_t *ifp, *ofp;
323*bc1f688bSRobert Mustacchi 	ctf_diff_t *cdp;
324*bc1f688bSRobert Mustacchi 	ctf_file_t *pifp = NULL;
325*bc1f688bSRobert Mustacchi 	ctf_file_t *pofp = NULL;
326*bc1f688bSRobert Mustacchi 
327*bc1f688bSRobert Mustacchi 	g_progname = basename(argv[0]);
328*bc1f688bSRobert Mustacchi 
329*bc1f688bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":aqtfolIp:F:O:P:T:")) != -1) {
330*bc1f688bSRobert Mustacchi 		switch (c) {
331*bc1f688bSRobert Mustacchi 		case 'a':
332*bc1f688bSRobert Mustacchi 			g_flag |= CTF_DIFF_ALL;
333*bc1f688bSRobert Mustacchi 			break;
334*bc1f688bSRobert Mustacchi 		case 't':
335*bc1f688bSRobert Mustacchi 			g_flag |= CTF_DIFF_TYPES;
336*bc1f688bSRobert Mustacchi 			break;
337*bc1f688bSRobert Mustacchi 		case 'f':
338*bc1f688bSRobert Mustacchi 			g_flag |= CTF_DIFF_FUNCS;
339*bc1f688bSRobert Mustacchi 			break;
340*bc1f688bSRobert Mustacchi 		case 'o':
341*bc1f688bSRobert Mustacchi 			g_flag |= CTF_DIFF_OBJS;
342*bc1f688bSRobert Mustacchi 			break;
343*bc1f688bSRobert Mustacchi 		case 'l':
344*bc1f688bSRobert Mustacchi 			g_flag |= CTF_DIFF_LABEL;
345*bc1f688bSRobert Mustacchi 			break;
346*bc1f688bSRobert Mustacchi 		case 'q':
347*bc1f688bSRobert Mustacchi 			g_onlydiff = B_TRUE;
348*bc1f688bSRobert Mustacchi 			break;
349*bc1f688bSRobert Mustacchi 		case 'p':
350*bc1f688bSRobert Mustacchi 			pifp = ctf_open(optarg, &err);
351*bc1f688bSRobert Mustacchi 			if (pifp == NULL) {
352*bc1f688bSRobert Mustacchi 				ctfdiff_fatal("failed to open parent input "
353*bc1f688bSRobert Mustacchi 				    "container %s: %s\n", optarg,
354*bc1f688bSRobert Mustacchi 				    ctf_errmsg(err));
355*bc1f688bSRobert Mustacchi 			}
356*bc1f688bSRobert Mustacchi 			break;
357*bc1f688bSRobert Mustacchi 		case 'F':
358*bc1f688bSRobert Mustacchi 			if (g_nextfunc == g_nfuncs) {
359*bc1f688bSRobert Mustacchi 				if (g_nfuncs == 0)
360*bc1f688bSRobert Mustacchi 					g_nfuncs = 16;
361*bc1f688bSRobert Mustacchi 				else
362*bc1f688bSRobert Mustacchi 					g_nfuncs *= 2;
363*bc1f688bSRobert Mustacchi 				g_funclist = realloc(g_funclist,
364*bc1f688bSRobert Mustacchi 				    sizeof (char *) * g_nfuncs);
365*bc1f688bSRobert Mustacchi 				if (g_funclist == NULL) {
366*bc1f688bSRobert Mustacchi 					ctfdiff_fatal("failed to allocate "
367*bc1f688bSRobert Mustacchi 					    "memory for the %dth -F option: "
368*bc1f688bSRobert Mustacchi 					    "%s\n", g_nexttype + 1,
369*bc1f688bSRobert Mustacchi 					    strerror(errno));
370*bc1f688bSRobert Mustacchi 				}
371*bc1f688bSRobert Mustacchi 			}
372*bc1f688bSRobert Mustacchi 			g_funclist[g_nextfunc] = optarg;
373*bc1f688bSRobert Mustacchi 			g_nextfunc++;
374*bc1f688bSRobert Mustacchi 			break;
375*bc1f688bSRobert Mustacchi 		case 'O':
376*bc1f688bSRobert Mustacchi 			if (g_nextobj == g_nobjs) {
377*bc1f688bSRobert Mustacchi 				if (g_nobjs == 0)
378*bc1f688bSRobert Mustacchi 					g_nobjs = 16;
379*bc1f688bSRobert Mustacchi 				else
380*bc1f688bSRobert Mustacchi 					g_nobjs *= 2;
381*bc1f688bSRobert Mustacchi 				g_objlist = realloc(g_objlist,
382*bc1f688bSRobert Mustacchi 				    sizeof (char *) * g_nobjs);
383*bc1f688bSRobert Mustacchi 				if (g_objlist == NULL) {
384*bc1f688bSRobert Mustacchi 					ctfdiff_fatal("failed to allocate "
385*bc1f688bSRobert Mustacchi 					    "memory for the %dth -F option: "
386*bc1f688bSRobert Mustacchi 					    "%s\n", g_nexttype + 1,
387*bc1f688bSRobert Mustacchi 					    strerror(errno));
388*bc1f688bSRobert Mustacchi 					return (CTFDIFF_EXIT_ERROR);
389*bc1f688bSRobert Mustacchi 				}
390*bc1f688bSRobert Mustacchi 			}
391*bc1f688bSRobert Mustacchi 			g_objlist[g_nextobj] = optarg;
392*bc1f688bSRobert Mustacchi 			g_nextobj++;
393*bc1f688bSRobert Mustacchi 			break;
394*bc1f688bSRobert Mustacchi 		case 'I':
395*bc1f688bSRobert Mustacchi 			flags |= CTF_DIFF_F_IGNORE_INTNAMES;
396*bc1f688bSRobert Mustacchi 			break;
397*bc1f688bSRobert Mustacchi 		case 'P':
398*bc1f688bSRobert Mustacchi 			pofp = ctf_open(optarg, &err);
399*bc1f688bSRobert Mustacchi 			if (pofp == NULL) {
400*bc1f688bSRobert Mustacchi 				ctfdiff_fatal("failed to open parent output "
401*bc1f688bSRobert Mustacchi 				    "container %s: %s\n", optarg,
402*bc1f688bSRobert Mustacchi 				    ctf_errmsg(err));
403*bc1f688bSRobert Mustacchi 			}
404*bc1f688bSRobert Mustacchi 			break;
405*bc1f688bSRobert Mustacchi 		case 'T':
406*bc1f688bSRobert Mustacchi 			if (g_nexttype == g_ntypes) {
407*bc1f688bSRobert Mustacchi 				if (g_ntypes == 0)
408*bc1f688bSRobert Mustacchi 					g_ntypes = 16;
409*bc1f688bSRobert Mustacchi 				else
410*bc1f688bSRobert Mustacchi 					g_ntypes *= 2;
411*bc1f688bSRobert Mustacchi 				g_typelist = realloc(g_typelist,
412*bc1f688bSRobert Mustacchi 				    sizeof (char *) * g_ntypes);
413*bc1f688bSRobert Mustacchi 				if (g_typelist == NULL) {
414*bc1f688bSRobert Mustacchi 					ctfdiff_fatal("failed to allocate "
415*bc1f688bSRobert Mustacchi 					    "memory for the %dth -T option: "
416*bc1f688bSRobert Mustacchi 					    "%s\n", g_nexttype + 1,
417*bc1f688bSRobert Mustacchi 					    strerror(errno));
418*bc1f688bSRobert Mustacchi 				}
419*bc1f688bSRobert Mustacchi 			}
420*bc1f688bSRobert Mustacchi 			g_typelist[g_nexttype] = optarg;
421*bc1f688bSRobert Mustacchi 			g_nexttype++;
422*bc1f688bSRobert Mustacchi 			break;
423*bc1f688bSRobert Mustacchi 		case ':':
424*bc1f688bSRobert Mustacchi 			ctfdiff_usage("Option -%c requires an operand\n",
425*bc1f688bSRobert Mustacchi 			    optopt);
426*bc1f688bSRobert Mustacchi 			return (CTFDIFF_EXIT_USAGE);
427*bc1f688bSRobert Mustacchi 		case '?':
428*bc1f688bSRobert Mustacchi 			ctfdiff_usage("Unknown option: -%c\n", optopt);
429*bc1f688bSRobert Mustacchi 			return (CTFDIFF_EXIT_USAGE);
430*bc1f688bSRobert Mustacchi 		}
431*bc1f688bSRobert Mustacchi 	}
432*bc1f688bSRobert Mustacchi 
433*bc1f688bSRobert Mustacchi 	argc -= optind - 1;
434*bc1f688bSRobert Mustacchi 	argv += optind - 1;
435*bc1f688bSRobert Mustacchi 
436*bc1f688bSRobert Mustacchi 	if (g_flag == 0)
437*bc1f688bSRobert Mustacchi 		g_flag = CTF_DIFF_DEFAULT;
438*bc1f688bSRobert Mustacchi 
439*bc1f688bSRobert Mustacchi 	if (argc != 3) {
440*bc1f688bSRobert Mustacchi 		ctfdiff_usage(NULL);
441*bc1f688bSRobert Mustacchi 		return (CTFDIFF_EXIT_USAGE);
442*bc1f688bSRobert Mustacchi 	}
443*bc1f688bSRobert Mustacchi 
444*bc1f688bSRobert Mustacchi 	if (g_nexttype != 0 && !(g_flag & CTF_DIFF_TYPES)) {
445*bc1f688bSRobert Mustacchi 		ctfdiff_usage("-T cannot be used if not diffing types\n");
446*bc1f688bSRobert Mustacchi 		return (CTFDIFF_EXIT_USAGE);
447*bc1f688bSRobert Mustacchi 	}
448*bc1f688bSRobert Mustacchi 
449*bc1f688bSRobert Mustacchi 	if (g_nextfunc != 0 && !(g_flag & CTF_DIFF_FUNCS)) {
450*bc1f688bSRobert Mustacchi 		ctfdiff_usage("-F cannot be used if not diffing functions\n");
451*bc1f688bSRobert Mustacchi 		return (CTFDIFF_EXIT_USAGE);
452*bc1f688bSRobert Mustacchi 	}
453*bc1f688bSRobert Mustacchi 
454*bc1f688bSRobert Mustacchi 	if (g_nextobj != 0 && !(g_flag & CTF_DIFF_OBJS)) {
455*bc1f688bSRobert Mustacchi 		ctfdiff_usage("-O cannot be used if not diffing objects\n");
456*bc1f688bSRobert Mustacchi 		return (CTFDIFF_EXIT_USAGE);
457*bc1f688bSRobert Mustacchi 	}
458*bc1f688bSRobert Mustacchi 
459*bc1f688bSRobert Mustacchi 	ifp = ctf_open(argv[1], &err);
460*bc1f688bSRobert Mustacchi 	if (ifp == NULL) {
461*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("failed to open %s: %s\n", argv[1],
462*bc1f688bSRobert Mustacchi 		    ctf_errmsg(err));
463*bc1f688bSRobert Mustacchi 	}
464*bc1f688bSRobert Mustacchi 	if (pifp != NULL) {
465*bc1f688bSRobert Mustacchi 		err = ctf_import(ifp, pifp);
466*bc1f688bSRobert Mustacchi 		if (err != 0) {
467*bc1f688bSRobert Mustacchi 			ctfdiff_fatal("failed to set parent container: %s\n",
468*bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(pifp)));
469*bc1f688bSRobert Mustacchi 		}
470*bc1f688bSRobert Mustacchi 	}
471*bc1f688bSRobert Mustacchi 	g_iname = argv[1];
472*bc1f688bSRobert Mustacchi 	g_ifp = ifp;
473*bc1f688bSRobert Mustacchi 
474*bc1f688bSRobert Mustacchi 	ofp = ctf_open(argv[2], &err);
475*bc1f688bSRobert Mustacchi 	if (ofp == NULL) {
476*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("failed to open %s: %s\n", argv[2],
477*bc1f688bSRobert Mustacchi 		    ctf_errmsg(err));
478*bc1f688bSRobert Mustacchi 	}
479*bc1f688bSRobert Mustacchi 
480*bc1f688bSRobert Mustacchi 	if (pofp != NULL) {
481*bc1f688bSRobert Mustacchi 		err = ctf_import(ofp, pofp);
482*bc1f688bSRobert Mustacchi 		if (err != 0) {
483*bc1f688bSRobert Mustacchi 			ctfdiff_fatal("failed to set parent container: %s\n",
484*bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(pofp)));
485*bc1f688bSRobert Mustacchi 		}
486*bc1f688bSRobert Mustacchi 	}
487*bc1f688bSRobert Mustacchi 	g_oname = argv[2];
488*bc1f688bSRobert Mustacchi 	g_ofp = ofp;
489*bc1f688bSRobert Mustacchi 
490*bc1f688bSRobert Mustacchi 	if (ctf_diff_init(ifp, ofp, &cdp) != 0) {
491*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("failed to initialize libctf diff engine: %s\n",
492*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(ifp)));
493*bc1f688bSRobert Mustacchi 	}
494*bc1f688bSRobert Mustacchi 
495*bc1f688bSRobert Mustacchi 	if (ctf_diff_setflags(cdp, flags) != 0) {
496*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("failed to set ctfdiff flags: %s\n",
497*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(ifp)));
498*bc1f688bSRobert Mustacchi 	}
499*bc1f688bSRobert Mustacchi 
500*bc1f688bSRobert Mustacchi 	err = 0;
501*bc1f688bSRobert Mustacchi 	if ((g_flag & CTF_DIFF_TYPES) && err != CTF_ERR)
502*bc1f688bSRobert Mustacchi 		err = ctf_diff_types(cdp, ctfdiff_cb, NULL);
503*bc1f688bSRobert Mustacchi 	if ((g_flag & CTF_DIFF_FUNCS) && err != CTF_ERR)
504*bc1f688bSRobert Mustacchi 		err = ctf_diff_functions(cdp, ctfdiff_func_cb, NULL);
505*bc1f688bSRobert Mustacchi 	if ((g_flag & CTF_DIFF_OBJS) && err != CTF_ERR)
506*bc1f688bSRobert Mustacchi 		err = ctf_diff_objects(cdp, ctfdiff_obj_cb, NULL);
507*bc1f688bSRobert Mustacchi 	if ((g_flag & CTF_DIFF_LABEL) && err != CTF_ERR)
508*bc1f688bSRobert Mustacchi 		err = ctfdiff_labels(ifp, ofp);
509*bc1f688bSRobert Mustacchi 
510*bc1f688bSRobert Mustacchi 	ctf_diff_fini(cdp);
511*bc1f688bSRobert Mustacchi 	if (err == CTF_ERR) {
512*bc1f688bSRobert Mustacchi 		ctfdiff_fatal("encountered a libctf error: %s!\n",
513*bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(ifp)));
514*bc1f688bSRobert Mustacchi 	}
515*bc1f688bSRobert Mustacchi 
516*bc1f688bSRobert Mustacchi 	return (g_different == B_TRUE ? CTFDIFF_EXIT_DIFFERENT :
517*bc1f688bSRobert Mustacchi 	    CTFDIFF_EXIT_SIMILAR);
518*bc1f688bSRobert Mustacchi }
519