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