summaryrefslogtreecommitdiff
path: root/usr/src/lib/libctf/common/ctf_diff.c
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2015-07-27 00:35:52 +0000
committerRobert Mustacchi <rm@joyent.com>2015-07-28 19:05:39 +0000
commit14c3d85bba96b10c225341f4c7f4af93c314b508 (patch)
tree8ef3a2513e220291581564d4db16bd5b4fbf127e /usr/src/lib/libctf/common/ctf_diff.c
parent9211d9b4c9ccc64292132e8e87c92ad6084b29a8 (diff)
downloadillumos-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.c95
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;