2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2015, Joyent, Inc.
17 * diff two CTF containers
28 #define CTFDIFF_NAMELEN 256
30 #define CTFDIFF_EXIT_SIMILAR 0
31 #define CTFDIFF_EXIT_DIFFERENT 1
32 #define CTFDIFF_EXIT_USAGE 2
33 #define CTFDIFF_EXIT_ERROR 3
35 typedef enum ctf_diff_cmd
{
36 CTF_DIFF_TYPES
= 0x01,
37 CTF_DIFF_FUNCS
= 0x02,
39 CTF_DIFF_DEFAULT
= 0x07,
40 CTF_DIFF_LABEL
= 0x08,
46 const char **dil_labels
;
49 static char *g_progname
;
50 static const char *g_iname
;
51 static ctf_file_t
*g_ifp
;
52 static const char *g_oname
;
53 static ctf_file_t
*g_ofp
;
54 static char **g_typelist
= NULL
;
55 static int g_nexttype
= 0;
56 static int g_ntypes
= 0;
57 static char **g_objlist
= NULL
;
58 static int g_nextfunc
= 0;
59 static int g_nfuncs
= 0;
60 static char **g_funclist
= NULL
;
61 static int g_nextobj
= 0;
62 static int g_nobjs
= 0;
63 static boolean_t g_onlydiff
= B_FALSE
;
64 static boolean_t g_different
= B_FALSE
;
65 static ctf_diff_cmd_t g_flag
= 0;
68 ctfdiff_fatal(const char *fmt
, ...)
72 (void) fprintf(stderr
, "%s: ", g_progname
);
74 (void) vfprintf(stderr
, fmt
, ap
);
77 exit(CTFDIFF_EXIT_ERROR
);
81 ctfdiff_fp_to_name(ctf_file_t
*fp
)
92 ctfdiff_func_cb(ctf_file_t
*ifp
, ulong_t iidx
, boolean_t similar
,
93 ctf_file_t
*ofp
, ulong_t oidx
, void *arg
)
95 char namebuf
[CTFDIFF_NAMELEN
];
97 if (similar
== B_TRUE
)
100 if (ctf_symbol_name(ifp
, iidx
, namebuf
, sizeof (namebuf
)) == NULL
) {
103 (void) printf("ctf container %s function %ld is different\n",
104 ctfdiff_fp_to_name(ifp
), iidx
);
106 if (g_nextfunc
!= 0) {
108 for (i
= 0; i
< g_nextfunc
; i
++) {
109 if (strcmp(g_funclist
[i
], namebuf
) == 0)
115 (void) printf("ctf container %s function %s (%ld) is "
116 "different\n", ctfdiff_fp_to_name(ifp
), namebuf
, iidx
);
119 g_different
= B_TRUE
;
124 ctfdiff_obj_cb(ctf_file_t
*ifp
, ulong_t iidx
, ctf_id_t iid
, boolean_t similar
,
125 ctf_file_t
*ofp
, ulong_t oidx
, ctf_id_t oid
, void *arg
)
127 char namebuf
[CTFDIFF_NAMELEN
];
129 if (similar
== B_TRUE
)
132 if (ctf_symbol_name(ifp
, iidx
, namebuf
, sizeof (namebuf
)) == NULL
) {
135 (void) printf("ctf container %s object %ld is different\n",
136 ctfdiff_fp_to_name(ifp
), iidx
);
138 if (g_nextobj
!= 0) {
140 for (i
= 0; i
< g_nextobj
; i
++) {
141 if (strcmp(g_objlist
[i
], namebuf
) == 0)
147 (void) printf("ctf container %s object %s (%ld) is different\n",
148 ctfdiff_fp_to_name(ifp
), namebuf
, iidx
);
151 g_different
= B_TRUE
;
156 ctfdiff_cb(ctf_file_t
*ifp
, ctf_id_t iid
, boolean_t similar
, ctf_file_t
*ofp
,
157 ctf_id_t oid
, void *arg
)
159 if (similar
== B_TRUE
)
162 if (ctf_type_kind(ifp
, iid
) == CTF_K_UNKNOWN
)
166 * Check if it's the type the user cares about.
168 if (g_nexttype
!= 0) {
170 char namebuf
[CTFDIFF_NAMELEN
];
172 if (ctf_type_name(ifp
, iid
, namebuf
, sizeof (namebuf
)) ==
174 ctfdiff_fatal("failed to obtain the name "
175 "of type %ld from %s: %s\n",
176 iid
, ctfdiff_fp_to_name(ifp
),
177 ctf_errmsg(ctf_errno(ifp
)));
180 for (i
= 0; i
< g_nexttype
; i
++) {
181 if (strcmp(g_typelist
[i
], namebuf
) == 0)
189 g_different
= B_TRUE
;
191 if (g_onlydiff
== B_TRUE
)
194 (void) printf("ctf container %s type %ld is different\n",
195 ctfdiff_fp_to_name(ifp
), iid
);
200 ctfdiff_labels_count(const char *name
, const ctf_lblinfo_t
*li
, void *arg
)
202 uint32_t *count
= arg
;
210 ctfdiff_labels_fill(const char *name
, const ctf_lblinfo_t
*li
, void *arg
)
212 ctfdiff_label_t
*dil
= arg
;
214 dil
->dil_labels
[dil
->dil_next
] = name
;
221 ctfdiff_labels(ctf_file_t
*ifp
, ctf_file_t
*ofp
)
224 uint32_t nilabel
, nolabel
, i
, j
;
225 ctfdiff_label_t idl
, odl
;
226 const char **ilptr
, **olptr
;
228 nilabel
= nolabel
= 0;
229 ret
= ctf_label_iter(ifp
, ctfdiff_labels_count
, &nilabel
);
232 ret
= ctf_label_iter(ofp
, ctfdiff_labels_count
, &nolabel
);
236 if (nilabel
!= nolabel
) {
237 (void) printf("ctf container %s labels differ from ctf "
238 "container %s\n", ctfdiff_fp_to_name(ifp
),
239 ctfdiff_fp_to_name(ofp
));
240 g_different
= B_TRUE
;
247 ilptr
= malloc(sizeof (char *) * nilabel
);
248 olptr
= malloc(sizeof (char *) * nolabel
);
249 if (ilptr
== NULL
|| olptr
== NULL
) {
250 ctfdiff_fatal("failed to allocate memory for label "
255 idl
.dil_labels
= ilptr
;
257 odl
.dil_labels
= olptr
;
259 if ((ret
= ctf_label_iter(ifp
, ctfdiff_labels_fill
, &idl
)) != 0)
261 if ((ret
= ctf_label_iter(ofp
, ctfdiff_labels_fill
, &odl
)) != 0)
264 for (i
= 0; i
< nilabel
; i
++) {
265 for (j
= 0; j
< nolabel
; j
++) {
266 if (strcmp(ilptr
[i
], olptr
[j
]) == 0)
271 (void) printf("ctf container %s labels differ from ctf "
272 "container %s\n", ctfdiff_fp_to_name(ifp
),
273 ctfdiff_fp_to_name(ofp
));
274 g_different
= B_TRUE
;
287 ctfdiff_usage(const char *fmt
, ...)
292 (void) fprintf(stderr
, "%s: ", g_progname
);
294 (void) vfprintf(stderr
, fmt
, ap
);
298 (void) fprintf(stderr
, "Usage: %s [-afIloqt] [-F function] [-O object]"
299 "[-p parent] [-P parent]\n"
300 "\t[-T type] file1 file2\n"
302 "\t-a diff label, types, objects, and functions\n"
303 "\t-f diff function type information\n"
304 "\t-F when diffing functions, only consider those named\n"
305 "\t-I ignore the names of integral types\n"
306 "\t-l diff CTF labels\n"
307 "\t-o diff global object type information\n"
308 "\t-O when diffing objects, only consider those named\n"
309 "\t-p set the CTF parent for file1\n"
310 "\t-P set the CTF parent for file2\n"
311 "\t-q set quiet mode (no diff information sent to stdout)\n"
312 "\t-t diff CTF type information\n"
313 "\t-T when diffing types, only consider those named\n",
318 main(int argc
, char *argv
[])
320 ctf_diff_flag_t flags
= 0;
322 ctf_file_t
*ifp
, *ofp
;
324 ctf_file_t
*pifp
= NULL
;
325 ctf_file_t
*pofp
= NULL
;
327 g_progname
= basename(argv
[0]);
329 while ((c
= getopt(argc
, argv
, ":aqtfolIp:F:O:P:T:")) != -1) {
332 g_flag
|= CTF_DIFF_ALL
;
335 g_flag
|= CTF_DIFF_TYPES
;
338 g_flag
|= CTF_DIFF_FUNCS
;
341 g_flag
|= CTF_DIFF_OBJS
;
344 g_flag
|= CTF_DIFF_LABEL
;
350 pifp
= ctf_open(optarg
, &err
);
352 ctfdiff_fatal("failed to open parent input "
353 "container %s: %s\n", optarg
,
358 if (g_nextfunc
== g_nfuncs
) {
363 g_funclist
= reallocarray(g_funclist
,
364 g_nfuncs
, sizeof (char *));
365 if (g_funclist
== NULL
) {
366 ctfdiff_fatal("failed to allocate "
367 "memory for the %dth -F option: "
368 "%s\n", g_nexttype
+ 1,
372 g_funclist
[g_nextfunc
] = optarg
;
376 if (g_nextobj
== g_nobjs
) {
381 g_objlist
= reallocarray(g_objlist
, g_nobjs
,
383 if (g_objlist
== NULL
) {
384 ctfdiff_fatal("failed to allocate "
385 "memory for the %dth -F option: "
386 "%s\n", g_nexttype
+ 1,
388 return (CTFDIFF_EXIT_ERROR
);
391 g_objlist
[g_nextobj
] = optarg
;
395 flags
|= CTF_DIFF_F_IGNORE_INTNAMES
;
398 pofp
= ctf_open(optarg
, &err
);
400 ctfdiff_fatal("failed to open parent output "
401 "container %s: %s\n", optarg
,
406 if (g_nexttype
== g_ntypes
) {
411 g_typelist
= reallocarray(g_typelist
,
412 g_ntypes
, sizeof (char *));
413 if (g_typelist
== NULL
) {
414 ctfdiff_fatal("failed to allocate "
415 "memory for the %dth -T option: "
416 "%s\n", g_nexttype
+ 1,
420 g_typelist
[g_nexttype
] = optarg
;
424 ctfdiff_usage("Option -%c requires an operand\n",
426 return (CTFDIFF_EXIT_USAGE
);
428 ctfdiff_usage("Unknown option: -%c\n", optopt
);
429 return (CTFDIFF_EXIT_USAGE
);
437 g_flag
= CTF_DIFF_DEFAULT
;
441 return (CTFDIFF_EXIT_USAGE
);
444 if (g_nexttype
!= 0 && !(g_flag
& CTF_DIFF_TYPES
)) {
445 ctfdiff_usage("-T cannot be used if not diffing types\n");
446 return (CTFDIFF_EXIT_USAGE
);
449 if (g_nextfunc
!= 0 && !(g_flag
& CTF_DIFF_FUNCS
)) {
450 ctfdiff_usage("-F cannot be used if not diffing functions\n");
451 return (CTFDIFF_EXIT_USAGE
);
454 if (g_nextobj
!= 0 && !(g_flag
& CTF_DIFF_OBJS
)) {
455 ctfdiff_usage("-O cannot be used if not diffing objects\n");
456 return (CTFDIFF_EXIT_USAGE
);
459 ifp
= ctf_open(argv
[1], &err
);
461 ctfdiff_fatal("failed to open %s: %s\n", argv
[1],
465 err
= ctf_import(ifp
, pifp
);
467 ctfdiff_fatal("failed to set parent container: %s\n",
468 ctf_errmsg(ctf_errno(pifp
)));
474 ofp
= ctf_open(argv
[2], &err
);
476 ctfdiff_fatal("failed to open %s: %s\n", argv
[2],
481 err
= ctf_import(ofp
, pofp
);
483 ctfdiff_fatal("failed to set parent container: %s\n",
484 ctf_errmsg(ctf_errno(pofp
)));
490 if (ctf_diff_init(ifp
, ofp
, &cdp
) != 0) {
491 ctfdiff_fatal("failed to initialize libctf diff engine: %s\n",
492 ctf_errmsg(ctf_errno(ifp
)));
495 if (ctf_diff_setflags(cdp
, flags
) != 0) {
496 ctfdiff_fatal("failed to set ctfdiff flags: %s\n",
497 ctf_errmsg(ctf_errno(ifp
)));
501 if ((g_flag
& CTF_DIFF_TYPES
) && err
!= CTF_ERR
)
502 err
= ctf_diff_types(cdp
, ctfdiff_cb
, NULL
);
503 if ((g_flag
& CTF_DIFF_FUNCS
) && err
!= CTF_ERR
)
504 err
= ctf_diff_functions(cdp
, ctfdiff_func_cb
, NULL
);
505 if ((g_flag
& CTF_DIFF_OBJS
) && err
!= CTF_ERR
)
506 err
= ctf_diff_objects(cdp
, ctfdiff_obj_cb
, NULL
);
507 if ((g_flag
& CTF_DIFF_LABEL
) && err
!= CTF_ERR
)
508 err
= ctfdiff_labels(ifp
, ofp
);
511 if (err
== CTF_ERR
) {
512 ctfdiff_fatal("encountered a libctf error: %s!\n",
513 ctf_errmsg(ctf_errno(ifp
)));
516 return (g_different
== B_TRUE
? CTFDIFF_EXIT_DIFFERENT
:
517 CTFDIFF_EXIT_SIMILAR
);