diff options
author | Robert Mustacchi <rm@joyent.com> | 2014-07-30 19:32:50 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2015-02-15 17:26:09 +0000 |
commit | b9050054bed684df58fc1c855197eec06a2036bf (patch) | |
tree | cc8ec42bb149c4c00b068fc8cab890ec5cdfc61a /usr/src/cmd/ctfdiff/ctfdiff.c | |
parent | f31c6fa33bcc9a608ce6f9ffd671ffc2b65a30ef (diff) | |
download | illumos-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.c | 382 |
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 : |