diff options
author | Robert Mustacchi <rm@joyent.com> | 2015-07-27 00:35:52 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2015-07-28 19:05:39 +0000 |
commit | 14c3d85bba96b10c225341f4c7f4af93c314b508 (patch) | |
tree | 8ef3a2513e220291581564d4db16bd5b4fbf127e /usr/src/lib/libctf/common/ctf_diff.c | |
parent | 9211d9b4c9ccc64292132e8e87c92ad6084b29a8 (diff) | |
download | illumos-joyent-14c3d85bba96b10c225341f4c7f4af93c314b508.tar.gz |
OS-4548 CTF Everywhere: Phase 1
OS-4549 ctfconvert should be implemented in terms of libctf
OS-4550 ctfconvert could convert multiple compilation units
OS-4553 want multi-threaded ctfmerge
OS-4552 Want general workq
OS-4551 Want general mergeq
OS-4554 ctfdiff doesn't properly handle unknown options
OS-4555 ctfdiff's symbols could be more consistently prefixed
OS-4048 new ctfmerge uses tmpfile after freeing it
OS-4556 ctfdump should drive on when incomplete files exist
OS-4557 ctf_add_encoded assigns() incorrect byte size to types
OS-4558 ctf_add_{struct,union,enum} can reuse forwards
OS-4559 ctf_add_{struct,union,enum} occasionally forget to dirty the ctf_file_t
OS-4560 ctf_add_member could better handle bitfields
OS-4561 ctf_type_size() reports wrong size for forwards
OS-4563 diffing CTF typedefs needs to walk multiple definitions
OS-4564 build scripts shouldn't hardcode CTF paths
OS-4565 ctf_fdcreate could be more flexible
OS-4566 Want libctf ctf_kind_name() function
OS-4567 Want libctf function to set struct/union size
OS-4568 Want ctfmerge altexec
Diffstat (limited to 'usr/src/lib/libctf/common/ctf_diff.c')
-rw-r--r-- | usr/src/lib/libctf/common/ctf_diff.c | 95 |
1 files changed, 90 insertions, 5 deletions
diff --git a/usr/src/lib/libctf/common/ctf_diff.c b/usr/src/lib/libctf/common/ctf_diff.c index e819fe02cb..d070488bbb 100644 --- a/usr/src/lib/libctf/common/ctf_diff.c +++ b/usr/src/lib/libctf/common/ctf_diff.c @@ -72,6 +72,8 @@ struct ctf_diff { ctf_file_t *cds_ofp; ctf_id_t *cds_forward; ctf_id_t *cds_reverse; + size_t cds_fsize; + size_t cds_rsize; ctf_diff_type_f cds_func; ctf_diff_guess_t *cds_guess; void *cds_arg; @@ -147,6 +149,39 @@ ctf_diff_number(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid) } /* + * Two typedefs are equivalent, if after we resolve a chain of typedefs, they + * point to equivalent types. This means that if a size_t is defined as follows: + * + * size_t -> ulong_t -> unsigned long + * size_t -> unsigned long + * + * That we'll ultimately end up treating them the same. + */ +static int +ctf_diff_typedef(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, + ctf_file_t *ofp, ctf_id_t oid) +{ + ctf_id_t iref = CTF_ERR, oref = CTF_ERR; + + while (ctf_type_kind(ifp, iid) == CTF_K_TYPEDEF) { + iref = ctf_type_reference(ifp, iid); + if (iref == CTF_ERR) + return (CTF_ERR); + iid = iref; + } + + while (ctf_type_kind(ofp, oid) == CTF_K_TYPEDEF) { + oref = ctf_type_reference(ofp, oid); + if (oref == CTF_ERR) + return (CTF_ERR); + oid = oref; + } + + VERIFY(iref != CTF_ERR && oref != CTF_ERR); + return (ctf_diff_type(cds, ifp, iref, ofp, oref)); +} + +/* * Two qualifiers are equivalent iff they point to two equivalent types. */ static int @@ -274,7 +309,8 @@ out: /* * Two structures are the same if every member is identical to its corresponding - * type, at the same offset, and has the same name. + * type, at the same offset, and has the same name, as well as them having the + * same overall size. */ static int ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, @@ -296,6 +332,9 @@ ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL) return (ctf_set_errno(oifp, ctf_errno(ofp))); + if (ctf_type_size(ifp, iid) != ctf_type_size(ofp, oid)) + return (B_TRUE); + if (LCTF_INFO_VLEN(ifp, itp->ctt_info) != LCTF_INFO_VLEN(ofp, otp->ctt_info)) return (B_TRUE); @@ -639,8 +678,10 @@ ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, case CTF_K_FORWARD: ret = ctf_diff_forward(ifp, iid, ofp, oid); break; - case CTF_K_POINTER: case CTF_K_TYPEDEF: + ret = ctf_diff_typedef(cds, ifp, iid, ofp, oid); + break; + case CTF_K_POINTER: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: @@ -664,9 +705,12 @@ ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, /* * Walk every type in the first container and try to find a match in the second. * If there is a match, then update both the forward and reverse mapping tables. + * + * The self variable tells us whether or not we should be comparing the input + * ctf container with itself or not. */ static int -ctf_diff_pass1(ctf_diff_t *cds) +ctf_diff_pass1(ctf_diff_t *cds, boolean_t self) { int i, j, diff; int istart, iend, jstart, jend; @@ -689,6 +733,17 @@ ctf_diff_pass1(ctf_diff_t *cds) for (i = istart; i <= iend; i++) { diff = B_TRUE; + + /* + * If we're doing a self diff for dedup purposes, then we want + * to ensure that we compare a type i with every type in the + * range, [ 1, i ). Yes, this does mean that when i equals 1, + * we won't compare anything. + */ + if (self == B_TRUE) { + jstart = istart; + jend = i - 1; + } for (j = jstart; j <= jend; j++) { ctf_diff_guess_t *cdg, *tofree; @@ -788,12 +843,14 @@ ctf_diff_init(ctf_file_t *ifp, ctf_file_t *ofp, ctf_diff_t **cdsp) ctf_free(cds, sizeof (ctf_diff_t)); return (ctf_set_errno(ifp, ENOMEM)); } + cds->cds_fsize = fsize; cds->cds_reverse = ctf_alloc(rsize); if (cds->cds_reverse == NULL) { ctf_free(cds->cds_forward, fsize); ctf_free(cds, sizeof (ctf_diff_t)); return (ctf_set_errno(ifp, ENOMEM)); } + cds->cds_rsize = rsize; bzero(cds->cds_forward, fsize); bzero(cds->cds_reverse, rsize); @@ -811,7 +868,7 @@ ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg) cds->cds_func = cb; cds->cds_arg = arg; - ret = ctf_diff_pass1(cds); + ret = ctf_diff_pass1(cds, B_FALSE); if (ret == 0) ret = ctf_diff_pass2(cds); @@ -821,12 +878,36 @@ ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg) return (ret); } +/* + * Do a diff where we're comparing a container with itself. In other words we'd + * like to know what types are actually duplicates of existing types in the + * container. + * + * Note this should remain private to libctf and not be exported in the public + * mapfile for the time being. + */ +int +ctf_diff_self(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg) +{ + if (cds->cds_ifp != cds->cds_ofp) + return (EINVAL); + + cds->cds_func = cb; + cds->cds_arg = arg; + + return (ctf_diff_pass1(cds, B_TRUE)); +} + + void ctf_diff_fini(ctf_diff_t *cds) { ctf_diff_guess_t *cdg; size_t fsize, rsize; + if (cds == NULL) + return; + cds->cds_ifp->ctf_refcnt--; cds->cds_ofp->ctf_refcnt--; @@ -855,6 +936,10 @@ ctf_diff_fini(ctf_diff_t *cds) cdg = cdg->cdg_next; ctf_free(tofree, sizeof (ctf_diff_guess_t)); } + if (cds->cds_forward != NULL) + ctf_free(cds->cds_forward, cds->cds_fsize); + if (cds->cds_reverse != NULL) + ctf_free(cds->cds_reverse, cds->cds_rsize); ctf_free(cds, sizeof (ctf_diff_t)); } @@ -867,7 +952,7 @@ ctf_diff_getflags(ctf_diff_t *cds) int ctf_diff_setflags(ctf_diff_t *cds, uint_t flags) { - if ((flags & ~CTF_DIFF_F_MASK) != 0) + if ((flags & ~CTF_DIFF_F_IGNORE_INTNAMES) != 0) return (ctf_set_errno(cds->cds_ifp, EINVAL)); cds->cds_flags = flags; |