summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ctfdiff/ctfdiff.c
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2014-07-30 19:32:50 +0000
committerRobert Mustacchi <rm@joyent.com>2015-02-15 17:26:09 +0000
commitb9050054bed684df58fc1c855197eec06a2036bf (patch)
treecc8ec42bb149c4c00b068fc8cab890ec5cdfc61a /usr/src/cmd/ctfdiff/ctfdiff.c
parentf31c6fa33bcc9a608ce6f9ffd671ffc2b65a30ef (diff)
downloadillumos-joyent-b9050054bed684df58fc1c855197eec06a2036bf.tar.gz
OS-3851 ctfdump should be written in terms of libctf
OS-3852 ctfdiff could be more useful OS-3853 ctfmerge and ctfconvert could have an altexec OS-3854 ctfmerge should be implemented in terms of libctf Reviewed by: Keith M Wesolowski <wesolows@foobazco.org>
Diffstat (limited to 'usr/src/cmd/ctfdiff/ctfdiff.c')
-rw-r--r--usr/src/cmd/ctfdiff/ctfdiff.c382
1 files changed, 335 insertions, 47 deletions
diff --git a/usr/src/cmd/ctfdiff/ctfdiff.c b/usr/src/cmd/ctfdiff/ctfdiff.c
index 9d4c65e698..2537c15bcb 100644
--- a/usr/src/cmd/ctfdiff/ctfdiff.c
+++ b/usr/src/cmd/ctfdiff/ctfdiff.c
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (c) 2014 Joyent, Inc. All rights reserved.
+ * Copyright (c) 2015, Joyent, Inc.
*/
/*
@@ -22,11 +22,31 @@
#include <errno.h>
#include <strings.h>
#include <libctf.h>
+#include <libgen.h>
+#include <stdarg.h>
+
+#define CTFDIFF_NAMELEN 256
#define CTFDIFF_EXIT_SIMILAR 0
#define CTFDIFF_EXIT_DIFFERENT 1
-#define CTFDIFF_EXIT_ERROR 2
+#define CTFDIFF_EXIT_USAGE 2
+#define CTFDIFF_EXIT_ERROR 3
+
+typedef enum ctf_diff_cmd {
+ CTF_DIFF_TYPES = 0x01,
+ CTF_DIFF_FUNCS = 0x02,
+ CTF_DIFF_OBJS = 0x04,
+ CTF_DIFF_DEFAULT = 0x07,
+ CTF_DIFF_LABEL = 0x08,
+ CTF_DIFF_ALL = 0x0f
+} ctf_diff_cmd_t;
+typedef struct {
+ int dil_next;
+ const char **dil_labels;
+} diff_label_t;
+
+static char *g_progname;
static const char *g_iname;
static ctf_file_t *g_ifp;
static const char *g_oname;
@@ -34,8 +54,28 @@ static ctf_file_t *g_ofp;
static char **g_typelist = NULL;
static int g_nexttype = 0;
static int g_ntypes = 0;
+static char **g_objlist = NULL;
+static int g_nextfunc = 0;
+static int g_nfuncs = 0;
+static char **g_funclist = NULL;
+static int g_nextobj = 0;
+static int g_nobjs = 0;
static boolean_t g_onlydiff = B_FALSE;
static boolean_t g_different = B_FALSE;
+static ctf_diff_cmd_t g_flag = 0;
+
+static void
+ctfdiff_fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ (void) fprintf(stderr, "%s: ", g_progname);
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(CTFDIFF_EXIT_ERROR);
+}
static const char *
fp_to_name(ctf_file_t *fp)
@@ -49,26 +89,92 @@ fp_to_name(ctf_file_t *fp)
/* ARGSUSED */
static void
+diff_func_cb(ctf_file_t *ifp, ulong_t iidx, boolean_t similar, ctf_file_t *ofp,
+ ulong_t oidx, void *arg)
+{
+ char namebuf[CTFDIFF_NAMELEN];
+
+ if (similar == B_TRUE)
+ return;
+
+ if (ctf_symbol_name(ifp, iidx, namebuf, sizeof (namebuf)) == NULL) {
+ if (g_nextfunc != 0)
+ return;
+ (void) printf("ctf container %s function %ld is different\n",
+ fp_to_name(ifp), iidx);
+ } else {
+ if (g_nextfunc != 0) {
+ int i;
+ for (i = 0; i < g_nextfunc; i++) {
+ if (strcmp(g_funclist[i], namebuf) == 0)
+ break;
+ }
+ if (i == g_nextfunc)
+ return;
+ }
+ (void) printf("ctf container %s function %s (%ld) is "
+ "different\n", fp_to_name(ifp), namebuf, iidx);
+ }
+
+ g_different = B_TRUE;
+}
+
+/* ARGSUSED */
+static void
+diff_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)
+{
+ char namebuf[CTFDIFF_NAMELEN];
+
+ if (similar == B_TRUE)
+ return;
+
+ if (ctf_symbol_name(ifp, iidx, namebuf, sizeof (namebuf)) == NULL) {
+ if (g_nextobj != 0)
+ return;
+ (void) printf("ctf container %s object %ld is different\n",
+ fp_to_name(ifp), iidx);
+ } else {
+ if (g_nextobj != 0) {
+ int i;
+ for (i = 0; i < g_nextobj; i++) {
+ if (strcmp(g_objlist[i], namebuf) == 0)
+ break;
+ }
+ if (i == g_nextobj)
+ return;
+ }
+ (void) printf("ctf container %s object %s (%ld) is different\n",
+ fp_to_name(ifp), namebuf, iidx);
+ }
+
+ g_different = B_TRUE;
+}
+
+/* ARGSUSED */
+static void
diff_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t similar, ctf_file_t *ofp,
ctf_id_t oid, void *arg)
{
if (similar == B_TRUE)
return;
+ if (ctf_type_kind(ifp, iid) == CTF_K_UNKNOWN)
+ return;
+
/*
* Check if it's the type the user cares about.
*/
if (g_nexttype != 0) {
int i;
- char namebuf[256];
+ char namebuf[CTFDIFF_NAMELEN];
if (ctf_type_name(ifp, iid, namebuf, sizeof (namebuf)) ==
NULL) {
- (void) fprintf(stderr, "failed to obtain the name "
+ ctfdiff_fatal("failed to obtain the name "
"of type %ld from %s: %s\n",
iid, fp_to_name(ifp),
ctf_errmsg(ctf_errno(ifp)));
- exit(CTFDIFF_EXIT_ERROR);
}
for (i = 0; i < g_nexttype; i++) {
@@ -85,13 +191,125 @@ diff_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t similar, ctf_file_t *ofp,
if (g_onlydiff == B_TRUE)
return;
- (void) printf("fp %s type %ld ", fp_to_name(ifp), iid);
- if (similar == B_TRUE) {
- (void) printf("is the same as fp %s type %ld\n",
- fp_to_name(ofp), oid);
- } else {
- (void) printf("is different\n");
+ (void) printf("ctf container %s type %ld is different\n",
+ fp_to_name(ifp), iid);
+}
+
+/* ARGSUSED */
+static int
+diff_labels_count(const char *name, const ctf_lblinfo_t *li, void *arg)
+{
+ uint32_t *count = arg;
+ *count = *count + 1;
+
+ return (0);
+}
+
+/* ARGSUSED */
+static int
+diff_labels_fill(const char *name, const ctf_lblinfo_t *li, void *arg)
+{
+ diff_label_t *dil = arg;
+
+ dil->dil_labels[dil->dil_next] = name;
+ dil->dil_next++;
+
+ return (0);
+}
+
+static int
+diff_labels(ctf_file_t *ifp, ctf_file_t *ofp)
+{
+ int ret;
+ uint32_t nilabel, nolabel, i, j;
+ diff_label_t idl, odl;
+ const char **ilptr, **olptr;
+
+ nilabel = nolabel = 0;
+ ret = ctf_label_iter(ifp, diff_labels_count, &nilabel);
+ if (ret == CTF_ERR)
+ return (ret);
+ ret = ctf_label_iter(ofp, diff_labels_count, &nolabel);
+ if (ret == CTF_ERR)
+ return (ret);
+
+ if (nilabel != nolabel) {
+ (void) printf("ctf container %s labels differ from ctf "
+ "container %s\n", fp_to_name(ifp), fp_to_name(ofp));
+ g_different = B_TRUE;
+ return (0);
+ }
+
+ if (nilabel == 0)
+ return (0);
+
+ ilptr = malloc(sizeof (char *) * nilabel);
+ olptr = malloc(sizeof (char *) * nolabel);
+ if (ilptr == NULL || olptr == NULL) {
+ ctfdiff_fatal("failed to allocate memory for label "
+ "comparison\n");
+ }
+
+ idl.dil_next = 0;
+ idl.dil_labels = ilptr;
+ odl.dil_next = 0;
+ odl.dil_labels = olptr;
+
+ if ((ret = ctf_label_iter(ifp, diff_labels_fill, &idl)) != 0)
+ goto out;
+ if ((ret = ctf_label_iter(ofp, diff_labels_fill, &odl)) != 0)
+ goto out;
+
+ for (i = 0; i < nilabel; i++) {
+ for (j = 0; j < nolabel; j++) {
+ if (strcmp(ilptr[i], olptr[j]) == 0)
+ break;
+ }
+
+ if (j == nolabel) {
+ (void) printf("ctf container %s labels differ from ctf "
+ "container %s\n", fp_to_name(ifp), fp_to_name(ofp));
+ g_different = B_TRUE;
+ break;
+ }
}
+
+ ret = 0;
+out:
+ free(ilptr);
+ free(olptr);
+ return (ret);
+}
+
+static void
+diff_usage(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ (void) fprintf(stderr, "%s: ", g_progname);
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+
+ (void) fprintf(stderr, "Usage: %s [-afIloqt] [-F function] [-O object]"
+ "[-p parent] [-P parent]\n"
+ "\t[-T type] file1 file2\n"
+ "\n"
+ "\t-a diff label, types, objects, and functions\n"
+ "\t-f diff function type information\n"
+ "\t-F when diffing functions, only consider those named\n"
+ "\t-I ignore the names of integral types\n"
+ "\t-l diff CTF labels\n"
+ "\t-o diff global object type information\n"
+ "\t-O when diffing objects, only consider those named\n"
+ "\t-p set the CTF parent for file1\n"
+ "\t-P set the CTF parent for file2\n"
+ "\t-q set quiet mode (no diff information sent to stdout)\n"
+ "\t-t diff CTF type information\n"
+ "\t-T when diffing types, only consider those named\n",
+ g_progname);
}
int
@@ -104,19 +322,72 @@ main(int argc, char *argv[])
ctf_file_t *pifp = NULL;
ctf_file_t *pofp = NULL;
- while ((c = getopt(argc, argv, "qIp:P:T:")) != -1) {
+ g_progname = basename(argv[0]);
+
+ while ((c = getopt(argc, argv, "aqtfolIp:F:O:P:T:")) != -1) {
switch (c) {
+ case 'a':
+ g_flag |= CTF_DIFF_ALL;
+ break;
+ case 't':
+ g_flag |= CTF_DIFF_TYPES;
+ break;
+ case 'f':
+ g_flag |= CTF_DIFF_FUNCS;
+ break;
+ case 'o':
+ g_flag |= CTF_DIFF_OBJS;
+ break;
+ case 'l':
+ g_flag |= CTF_DIFF_LABEL;
+ break;
case 'q':
g_onlydiff = B_TRUE;
break;
case 'p':
pifp = ctf_open(optarg, &err);
if (pifp == NULL) {
- (void) fprintf(stderr, "ctfdiff: failed to "
- "open parent input container %s: %s\n",
- optarg, ctf_errmsg(err));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to open parent input "
+ "container %s: %s\n", optarg,
+ ctf_errmsg(err));
+ }
+ break;
+ case 'F':
+ if (g_nextfunc == g_nfuncs) {
+ if (g_nfuncs == 0)
+ g_nfuncs = 16;
+ else
+ g_nfuncs *= 2;
+ g_funclist = realloc(g_funclist,
+ sizeof (char *) * g_nfuncs);
+ if (g_funclist == NULL) {
+ ctfdiff_fatal("failed to allocate "
+ "memory for the %dth -F option: "
+ "%s\n", g_nexttype + 1,
+ strerror(errno));
+ }
}
+ g_funclist[g_nextfunc] = optarg;
+ g_nextfunc++;
+ break;
+ case 'O':
+ if (g_nextobj == g_nobjs) {
+ if (g_nobjs == 0)
+ g_nobjs = 16;
+ else
+ g_nobjs *= 2;
+ g_objlist = realloc(g_objlist,
+ sizeof (char *) * g_nobjs);
+ if (g_objlist == NULL) {
+ ctfdiff_fatal("failed to allocate "
+ "memory for the %dth -F option: "
+ "%s\n", g_nexttype + 1,
+ strerror(errno));
+ return (CTFDIFF_EXIT_ERROR);
+ }
+ }
+ g_objlist[g_nextobj] = optarg;
+ g_nextobj++;
break;
case 'I':
flags |= CTF_DIFF_F_IGNORE_INTNAMES;
@@ -124,10 +395,9 @@ main(int argc, char *argv[])
case 'P':
pofp = ctf_open(optarg, &err);
if (pofp == NULL) {
- (void) fprintf(stderr, "ctfdiff: failed to "
- "open parent output container %s: %s\n",
- optarg, ctf_errmsg(err));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to open parent output "
+ "container %s: %s\n", optarg,
+ ctf_errmsg(err));
}
break;
case 'T':
@@ -139,10 +409,10 @@ main(int argc, char *argv[])
g_typelist = realloc(g_typelist,
sizeof (char *) * g_ntypes);
if (g_typelist == NULL) {
- (void) fprintf(stderr, "ctfdiff: "
- "failed to allocate memory for "
- "the %dth -t option: %s\n",
- g_nexttype + 1, strerror(errno));
+ ctfdiff_fatal("failed to allocate "
+ "memory for the %dth -T option: "
+ "%s\n", g_nexttype + 1,
+ strerror(errno));
}
}
g_typelist[g_nexttype] = optarg;
@@ -153,24 +423,39 @@ main(int argc, char *argv[])
argc -= optind - 1;
argv += optind - 1;
+ if (g_flag == 0)
+ g_flag = CTF_DIFF_DEFAULT;
+
if (argc != 3) {
- (void) fprintf(stderr, "usage: ctfdiff [-qI] [-p parent] "
- "[-P parent] [-T type]... input output");
- return (CTFDIFF_EXIT_ERROR);
+ diff_usage(NULL);
+ return (CTFDIFF_EXIT_USAGE);
+ }
+
+ if (g_nexttype != 0 && !(g_flag & CTF_DIFF_TYPES)) {
+ diff_usage("-T cannot be used if not diffing types\n");
+ return (CTFDIFF_EXIT_USAGE);
+ }
+
+ if (g_nextfunc != 0 && !(g_flag & CTF_DIFF_FUNCS)) {
+ diff_usage("-F cannot be used if not diffing functions\n");
+ return (CTFDIFF_EXIT_USAGE);
+ }
+
+ if (g_nextobj != 0 && !(g_flag & CTF_DIFF_OBJS)) {
+ diff_usage("-O cannot be used if not diffing objects\n");
+ return (CTFDIFF_EXIT_USAGE);
}
ifp = ctf_open(argv[1], &err);
if (ifp == NULL) {
- (void) fprintf(stderr, "ctfdiff: failed to open %s: %s\n",
- argv[1], ctf_errmsg(err));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to open %s: %s\n", argv[1],
+ ctf_errmsg(err));
}
if (pifp != NULL) {
err = ctf_import(ifp, pifp);
if (err != 0) {
- (void) fprintf(stderr, "ctfdiff: failed to set parent "
- "container: %s\n", ctf_errmsg(ctf_errno(pifp)));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to set parent container: %s\n",
+ ctf_errmsg(ctf_errno(pifp)));
}
}
g_iname = argv[1];
@@ -178,41 +463,44 @@ main(int argc, char *argv[])
ofp = ctf_open(argv[2], &err);
if (ofp == NULL) {
- (void) fprintf(stderr, "ctfdiff: failed to open %s: %s\n",
- argv[2], ctf_errmsg(err));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to open %s: %s\n", argv[2],
+ ctf_errmsg(err));
}
if (pofp != NULL) {
err = ctf_import(ofp, pofp);
if (err != 0) {
- (void) fprintf(stderr, "ctfdiff: failed to set parent "
- "container: %s\n", ctf_errmsg(ctf_errno(pofp)));
- return (CTFDIFF_EXIT_ERROR);
+ ctfdiff_fatal("failed to set parent container: %s\n",
+ ctf_errmsg(ctf_errno(pofp)));
}
}
g_oname = argv[2];
g_ofp = ofp;
if (ctf_diff_init(ifp, ofp, &cdp) != 0) {
- (void) fprintf(stderr,
- "ctfdiff: failed to initialize libctf diff engine: %s\n",
+ ctfdiff_fatal("failed to initialize libctf diff engine: %s\n",
ctf_errmsg(ctf_errno(ifp)));
- return (CTFDIFF_EXIT_ERROR);
}
if (ctf_diff_setflags(cdp, flags) != 0) {
- (void) fprintf(stderr,
- "ctfdiff: failed to set ctfdiff flags: %s\n",
+ ctfdiff_fatal("failed to set ctfdiff flags: %s\n",
ctf_errmsg(ctf_errno(ifp)));
}
- err = ctf_diff_types(cdp, diff_cb, NULL);
+ err = 0;
+ if ((g_flag & CTF_DIFF_TYPES) && err != CTF_ERR)
+ err = ctf_diff_types(cdp, diff_cb, NULL);
+ if ((g_flag & CTF_DIFF_FUNCS) && err != CTF_ERR)
+ err = ctf_diff_functions(cdp, diff_func_cb, NULL);
+ if ((g_flag & CTF_DIFF_OBJS) && err != CTF_ERR)
+ err = ctf_diff_objects(cdp, diff_obj_cb, NULL);
+ if ((g_flag & CTF_DIFF_LABEL) && err != CTF_ERR)
+ err = diff_labels(ifp, ofp);
+
ctf_diff_fini(cdp);
if (err == CTF_ERR) {
- (void) fprintf(stderr, "encountered a libctf error: %s!\n",
+ ctfdiff_fatal("encountered a libctf error: %s!\n",
ctf_errmsg(ctf_errno(ifp)));
- return (CTFDIFF_EXIT_ERROR);
}
return (g_different == B_TRUE ? CTFDIFF_EXIT_DIFFERENT :