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. All rights reserved.
17 * The following ia a basic overview of how we diff types in containers (the
18 * generally interesting part of diff, and what's used by merge). We maintain
19 * two mapping tables, a table of forward mappings (src->dest), and a reverse
20 * mapping (dest->src). Both are initialized to contain no mapping, and can also
21 * be updated to contain a negative mapping.
23 * What we do first is iterate over each type in the src container, and compare
24 * it with a type in the destination container. This may involve doing recursive
25 * comparisons -- which can involve cycles. To deal with this, whenever we
26 * encounter something which may be cyclic, we insert a guess. In other words,
27 * we assume that it may be true. This is necessary for the classic case of the
28 * following structure:
31 * struct foo *foo_next;
34 * If it turns out that we were wrong, we discard our guesses.
36 * If we find that a given type in src has no corresponding entry in dst, we
37 * then mark its map as CTF_ERR (-1) to indicate that it has *no* match, as
38 * opposed to the default value of 0, which indicates an unknown match.
39 * Once we've done the first iteration through src, we know at that point in
40 * time whether everything in dst is similar or not and can simply walk over it
41 * and don't have to do any additional checks.
46 #include <sys/debug.h>
48 typedef struct ctf_diff_func
{
54 typedef struct ctf_diff_obj
{
61 typedef struct ctf_diff_guess
{
62 struct ctf_diff_guess
*cdg_next
;
67 /* typedef in libctf.h */
70 boolean_t cds_tvalid
; /* types valid */
73 ctf_id_t
*cds_forward
;
74 ctf_id_t
*cds_reverse
;
77 ctf_diff_type_f cds_func
;
78 ctf_diff_guess_t
*cds_guess
;
84 ctf_diff_func_t
*cds_ifuncs
;
85 ctf_diff_func_t
*cds_ofuncs
;
86 boolean_t cds_ffillip
;
92 ctf_diff_obj_t
*cds_iobj
;
93 ctf_diff_obj_t
*cds_oobj
;
94 boolean_t cds_ofillip
;
98 #define TINDEX(tid) (tid - 1)
103 static int ctf_diff_type(ctf_diff_t
*, ctf_file_t
*, ctf_id_t
, ctf_file_t
*,
107 ctf_diff_name(ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
, ctf_id_t oid
)
109 const char *iname
, *oname
;
110 const ctf_type_t
*itp
, *otp
;
112 if ((itp
= ctf_lookup_by_id(&ifp
, iid
)) == NULL
)
115 if ((otp
= ctf_lookup_by_id(&ofp
, oid
)) == NULL
)
116 return (ctf_set_errno(ifp
, iid
));
118 iname
= ctf_strptr(ifp
, itp
->ctt_name
);
119 oname
= ctf_strptr(ofp
, otp
->ctt_name
);
121 if ((iname
== NULL
|| oname
== NULL
) && (iname
!= oname
))
124 /* Two anonymous names are the same */
125 if (iname
== NULL
&& oname
== NULL
)
128 return (strcmp(iname
, oname
) == 0 ? B_FALSE
: B_TRUE
);
132 * For floats and ints
135 ctf_diff_number(ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
, ctf_id_t oid
)
137 ctf_encoding_t ien
, den
;
139 if (ctf_type_encoding(ifp
, iid
, &ien
) != 0)
142 if (ctf_type_encoding(ofp
, oid
, &den
) != 0)
143 return (ctf_set_errno(ifp
, iid
));
145 if (bcmp(&ien
, &den
, sizeof (ctf_encoding_t
)) != 0)
152 * Two typedefs are equivalent, if after we resolve a chain of typedefs, they
153 * point to equivalent types. This means that if a size_t is defined as follows:
155 * size_t -> ulong_t -> unsigned long
156 * size_t -> unsigned long
158 * That we'll ultimately end up treating them the same.
161 ctf_diff_typedef(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
,
162 ctf_file_t
*ofp
, ctf_id_t oid
)
164 ctf_id_t iref
= CTF_ERR
, oref
= CTF_ERR
;
166 while (ctf_type_kind(ifp
, iid
) == CTF_K_TYPEDEF
) {
167 iref
= ctf_type_reference(ifp
, iid
);
173 while (ctf_type_kind(ofp
, oid
) == CTF_K_TYPEDEF
) {
174 oref
= ctf_type_reference(ofp
, oid
);
180 VERIFY(iref
!= CTF_ERR
&& oref
!= CTF_ERR
);
181 return (ctf_diff_type(cds
, ifp
, iref
, ofp
, oref
));
185 * Two qualifiers are equivalent iff they point to two equivalent types.
188 ctf_diff_qualifier(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
,
189 ctf_file_t
*ofp
, ctf_id_t oid
)
193 iref
= ctf_type_reference(ifp
, iid
);
197 oref
= ctf_type_reference(ofp
, oid
);
199 return (ctf_set_errno(ifp
, ctf_errno(ofp
)));
201 return (ctf_diff_type(cds
, ifp
, iref
, ofp
, oref
));
205 * Two arrays are the same iff they have the same type for contents, the same
206 * type for the index, and the same number of elements.
209 ctf_diff_array(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
,
213 ctf_arinfo_t iar
, oar
;
215 if (ctf_array_info(ifp
, iid
, &iar
) == CTF_ERR
)
218 if (ctf_array_info(ofp
, oid
, &oar
) == CTF_ERR
)
219 return (ctf_set_errno(ifp
, ctf_errno(ofp
)));
221 ret
= ctf_diff_type(cds
, ifp
, iar
.ctr_contents
, ofp
, oar
.ctr_contents
);
225 if (iar
.ctr_nelems
!= oar
.ctr_nelems
)
229 * If we're ignoring integer types names, then we're trying to do a bit
230 * of a logical diff and we don't really care about the fact that the
231 * index element might not be the same here, what we care about are the
232 * number of elements and that they're the same type.
234 if ((cds
->cds_flags
& CTF_DIFF_F_IGNORE_INTNAMES
) == 0) {
235 ret
= ctf_diff_type(cds
, ifp
, iar
.ctr_index
, ofp
,
245 * Two function pointers are the same if the following is all true:
247 * o They have the same return type
248 * o They have the same number of arguments
249 * o The arguments are of the same type
250 * o They have the same flags
253 ctf_diff_fptr(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
,
257 ctf_funcinfo_t ifunc
, ofunc
;
258 ctf_id_t
*iids
, *oids
;
260 if (ctf_func_info_by_id(ifp
, iid
, &ifunc
) == CTF_ERR
)
263 if (ctf_func_info_by_id(ofp
, oid
, &ofunc
) == CTF_ERR
)
264 return (ctf_set_errno(ifp
, ctf_errno(ofp
)));
266 if (ifunc
.ctc_argc
!= ofunc
.ctc_argc
)
269 if (ifunc
.ctc_flags
!= ofunc
.ctc_flags
)
272 ret
= ctf_diff_type(cds
, ifp
, ifunc
.ctc_return
, ofp
, ofunc
.ctc_return
);
276 iids
= ctf_alloc(sizeof (ctf_id_t
) * ifunc
.ctc_argc
);
278 return (ctf_set_errno(ifp
, ENOMEM
));
280 oids
= ctf_alloc(sizeof (ctf_id_t
) * ifunc
.ctc_argc
);
282 ctf_free(iids
, sizeof (ctf_id_t
) * ifunc
.ctc_argc
);
283 return (ctf_set_errno(ifp
, ENOMEM
));
286 if (ctf_func_args_by_id(ifp
, iid
, ifunc
.ctc_argc
, iids
) == CTF_ERR
) {
291 if (ctf_func_args_by_id(ofp
, oid
, ofunc
.ctc_argc
, oids
) == CTF_ERR
) {
292 ret
= ctf_set_errno(ifp
, ctf_errno(ofp
));
297 for (i
= 0; i
< ifunc
.ctc_argc
; i
++) {
298 ret
= ctf_diff_type(cds
, ifp
, iids
[i
], ofp
, oids
[i
]);
305 ctf_free(iids
, sizeof (ctf_id_t
) * ifunc
.ctc_argc
);
306 ctf_free(oids
, sizeof (ctf_id_t
) * ofunc
.ctc_argc
);
311 * Two structures are the same if every member is identical to its corresponding
312 * type, at the same offset, and has the same name, as well as them having the
316 ctf_diff_struct(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
,
320 const ctf_type_t
*itp
, *otp
;
321 ssize_t isize
, iincr
, osize
, oincr
;
322 const ctf_member_t
*imp
, *omp
;
323 const ctf_lmember_t
*ilmp
, *olmp
;
325 ctf_diff_guess_t
*cdg
;
329 if ((itp
= ctf_lookup_by_id(&ifp
, iid
)) == NULL
)
332 if ((otp
= ctf_lookup_by_id(&ofp
, oid
)) == NULL
)
333 return (ctf_set_errno(oifp
, ctf_errno(ofp
)));
335 if (ctf_type_size(ifp
, iid
) != ctf_type_size(ofp
, oid
))
338 if (LCTF_INFO_VLEN(ifp
, itp
->ctt_info
) !=
339 LCTF_INFO_VLEN(ofp
, otp
->ctt_info
))
342 (void) ctf_get_ctt_size(ifp
, itp
, &isize
, &iincr
);
343 (void) ctf_get_ctt_size(ofp
, otp
, &osize
, &oincr
);
345 if (ifp
->ctf_version
== CTF_VERSION_1
|| isize
< CTF_LSTRUCT_THRESH
) {
346 imp
= (const ctf_member_t
*)((uintptr_t)itp
+ iincr
);
350 ilmp
= (const ctf_lmember_t
*)((uintptr_t)itp
+ iincr
);
353 if (ofp
->ctf_version
== CTF_VERSION_1
|| osize
< CTF_LSTRUCT_THRESH
) {
354 omp
= (const ctf_member_t
*)((uintptr_t)otp
+ oincr
);
358 olmp
= (const ctf_lmember_t
*)((uintptr_t)otp
+ oincr
);
362 * Insert our assumption that they're equal for the moment.
364 cdg
= ctf_alloc(sizeof (ctf_diff_guess_t
));
366 return (ctf_set_errno(ifp
, ENOMEM
));
369 cdg
->cdg_next
= cds
->cds_guess
;
370 cds
->cds_guess
= cdg
;
371 cds
->cds_forward
[TINDEX(iid
)] = oid
;
372 cds
->cds_reverse
[TINDEX(oid
)] = iid
;
374 for (n
= LCTF_INFO_VLEN(ifp
, itp
->ctt_info
); n
!= 0; n
--) {
375 const char *iname
, *oname
;
377 ctf_id_t itype
, otype
;
381 iname
= ctf_strptr(ifp
, imp
->ctm_name
);
382 ioff
= imp
->ctm_offset
;
383 itype
= imp
->ctm_type
;
385 iname
= ctf_strptr(ifp
, ilmp
->ctlm_name
);
386 ioff
= CTF_LMEM_OFFSET(ilmp
);
387 itype
= ilmp
->ctlm_type
;
391 oname
= ctf_strptr(ofp
, omp
->ctm_name
);
392 ooff
= omp
->ctm_offset
;
393 otype
= omp
->ctm_type
;
395 oname
= ctf_strptr(ofp
, olmp
->ctlm_name
);
396 ooff
= CTF_LMEM_OFFSET(olmp
);
397 otype
= olmp
->ctlm_type
;
403 if (strcmp(iname
, oname
) != 0) {
406 ret
= ctf_diff_type(cds
, ifp
, itype
, ofp
, otype
);
407 if (ret
!= B_FALSE
) {
411 /* Advance our pointers */
426 * Two unions are the same if they have the same set of members. This is similar
427 * to, but slightly different from a struct. The offsets of members don't
428 * matter. However, their is no guarantee of ordering so we have to fall back to
429 * doing an O(N^2) scan.
431 typedef struct ctf_diff_union_member
{
432 ctf_diff_t
*cdum_cds
;
434 ctf_file_t
*cdum_iterfp
;
435 const char *cdum_name
;
438 } ctf_diff_union_member_t
;
440 typedef struct ctf_diff_union_fp
{
441 ctf_diff_t
*cduf_cds
;
442 ctf_file_t
*cduf_curfp
;
443 ctf_file_t
*cduf_altfp
;
446 } ctf_diff_union_fp_t
;
450 ctf_diff_union_check_member(const char *name
, ctf_id_t id
, ulong_t off
,
454 ctf_diff_union_member_t
*cdump
= arg
;
456 if (strcmp(name
, cdump
->cdum_name
) != 0)
459 ret
= ctf_diff_type(cdump
->cdum_cds
, cdump
->cdum_fp
, cdump
->cdum_type
,
460 cdump
->cdum_iterfp
, id
);
461 if (ret
== CTF_ERR
) {
462 cdump
->cdum_ret
= CTF_ERR
;
466 if (ret
== B_FALSE
) {
467 cdump
->cdum_ret
= B_FALSE
;
468 /* Return non-zero to stop iteration as we have a match */
477 ctf_diff_union_check_fp(const char *name
, ctf_id_t id
, ulong_t off
, void *arg
)
480 ctf_diff_union_member_t cdum
;
481 ctf_diff_union_fp_t
*cdufp
= arg
;
483 cdum
.cdum_cds
= cdufp
->cduf_cds
;
484 cdum
.cdum_fp
= cdufp
->cduf_curfp
;
485 cdum
.cdum_iterfp
= cdufp
->cduf_altfp
;
486 cdum
.cdum_name
= name
;
488 cdum
.cdum_ret
= B_TRUE
;
490 ret
= ctf_member_iter(cdum
.cdum_iterfp
, cdufp
->cduf_type
,
491 ctf_diff_union_check_member
, &cdum
);
492 if (ret
== 0 || cdum
.cdum_ret
== CTF_ERR
) {
493 /* No match found or error, terminate now */
494 cdufp
->cduf_ret
= cdum
.cdum_ret
;
496 } else if (ret
== CTF_ERR
) {
497 (void) ctf_set_errno(cdum
.cdum_fp
, ctf_errno(cdum
.cdum_iterfp
));
498 cdufp
->cduf_ret
= CTF_ERR
;
501 ASSERT(cdum
.cdum_ret
== B_FALSE
);
502 cdufp
->cduf_ret
= cdum
.cdum_ret
;
508 ctf_diff_union(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
,
512 const ctf_type_t
*itp
, *otp
;
513 ctf_diff_union_fp_t cduf
;
514 ctf_diff_guess_t
*cdg
;
518 if ((itp
= ctf_lookup_by_id(&ifp
, iid
)) == NULL
)
520 if ((otp
= ctf_lookup_by_id(&ofp
, oid
)) == NULL
)
521 return (ctf_set_errno(oifp
, ctf_errno(ofp
)));
523 if (LCTF_INFO_VLEN(ifp
, itp
->ctt_info
) !=
524 LCTF_INFO_VLEN(ofp
, otp
->ctt_info
))
527 cdg
= ctf_alloc(sizeof (ctf_diff_guess_t
));
529 return (ctf_set_errno(ifp
, ENOMEM
));
532 cdg
->cdg_next
= cds
->cds_guess
;
533 cds
->cds_guess
= cdg
;
534 cds
->cds_forward
[TINDEX(iid
)] = oid
;
535 cds
->cds_reverse
[TINDEX(oid
)] = iid
;
538 cduf
.cduf_curfp
= ifp
;
539 cduf
.cduf_altfp
= ofp
;
540 cduf
.cduf_type
= oid
;
541 cduf
.cduf_ret
= B_TRUE
;
542 ret
= ctf_member_iter(ifp
, iid
, ctf_diff_union_check_fp
, &cduf
);
550 * Two enums are equivalent if they share the same underlying type and they have
551 * the same set of members.
554 ctf_diff_enum(ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
, ctf_id_t oid
)
557 const ctf_type_t
*itp
, *otp
;
558 ssize_t iincr
, oincr
;
559 const ctf_enum_t
*iep
, *oep
;
563 if ((itp
= ctf_lookup_by_id(&ifp
, iid
)) == NULL
)
565 if ((otp
= ctf_lookup_by_id(&ofp
, oid
)) == NULL
)
566 return (ctf_set_errno(oifp
, ctf_errno(ofp
)));
568 if (LCTF_INFO_VLEN(ifp
, itp
->ctt_info
) !=
569 LCTF_INFO_VLEN(ofp
, otp
->ctt_info
))
572 (void) ctf_get_ctt_size(ifp
, itp
, NULL
, &iincr
);
573 (void) ctf_get_ctt_size(ofp
, otp
, NULL
, &oincr
);
574 iep
= (const ctf_enum_t
*)((uintptr_t)itp
+ iincr
);
575 oep
= (const ctf_enum_t
*)((uintptr_t)otp
+ oincr
);
577 for (n
= LCTF_INFO_VLEN(ifp
, itp
->ctt_info
); n
!= 0;
579 if (strcmp(ctf_strptr(ifp
, iep
->cte_name
),
580 ctf_strptr(ofp
, oep
->cte_name
)) != 0)
583 if (iep
->cte_value
!= oep
->cte_value
)
591 * Two forwards are equivalent in one of two cases. If both are forwards, than
592 * they are the same. Otherwise, they're equivalent if one is a struct or union
593 * and the other is a forward.
596 ctf_diff_forward(ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
, ctf_id_t oid
)
600 ikind
= ctf_type_kind(ifp
, iid
);
601 okind
= ctf_type_kind(ofp
, oid
);
603 if (ikind
== okind
) {
604 ASSERT(ikind
== CTF_K_FORWARD
);
606 } else if (ikind
== CTF_K_FORWARD
) {
607 return (okind
!= CTF_K_UNION
&& okind
!= CTF_K_STRUCT
);
609 return (ikind
!= CTF_K_UNION
&& ikind
!= CTF_K_STRUCT
);
614 * Are two types equivalent?
617 ctf_diff_type(ctf_diff_t
*cds
, ctf_file_t
*ifp
, ctf_id_t iid
, ctf_file_t
*ofp
,
620 int ret
, ikind
, okind
;
622 /* Do a quick short circuit */
623 if (ifp
== ofp
&& iid
== oid
)
627 * Check if it's something we've already encountered in a forward
628 * reference or forward negative table. Also double check the reverse
631 if (cds
->cds_forward
[TINDEX(iid
)] == oid
)
633 if (cds
->cds_forward
[TINDEX(iid
)] != 0)
635 if (cds
->cds_reverse
[TINDEX(oid
)] == iid
)
637 if ((cds
->cds_flags
& CTF_DIFF_F_IGNORE_INTNAMES
) == 0 &&
638 cds
->cds_reverse
[TINDEX(oid
)] != 0)
641 ikind
= ctf_type_kind(ifp
, iid
);
642 okind
= ctf_type_kind(ofp
, oid
);
644 if (ikind
!= okind
&&
645 ikind
!= CTF_K_FORWARD
&& okind
!= CTF_K_FORWARD
)
649 if ((ret
= ctf_diff_name(ifp
, iid
, ofp
, oid
)) != B_FALSE
) {
650 if (ikind
!= okind
|| ikind
!= CTF_K_INTEGER
||
651 (cds
->cds_flags
& CTF_DIFF_F_IGNORE_INTNAMES
) == 0)
655 if (ikind
== CTF_K_FORWARD
|| okind
== CTF_K_FORWARD
)
656 return (ctf_diff_forward(ifp
, iid
, ofp
, oid
));
661 ret
= ctf_diff_number(ifp
, iid
, ofp
, oid
);
664 ret
= ctf_diff_array(cds
, ifp
, iid
, ofp
, oid
);
667 ret
= ctf_diff_fptr(cds
, ifp
, iid
, ofp
, oid
);
670 ret
= ctf_diff_struct(cds
, ifp
, iid
, ofp
, oid
);
673 ret
= ctf_diff_union(cds
, ifp
, iid
, ofp
, oid
);
676 ret
= ctf_diff_enum(ifp
, iid
, ofp
, oid
);
679 ret
= ctf_diff_forward(ifp
, iid
, ofp
, oid
);
682 ret
= ctf_diff_typedef(cds
, ifp
, iid
, ofp
, oid
);
688 ret
= ctf_diff_qualifier(cds
, ifp
, iid
, ofp
, oid
);
692 * The current CTF tools use CTF_K_UNKNOWN as a padding type. We
693 * always declare two instances of CTF_K_UNKNOWN as different,
694 * even though this leads to additional diff noise.
706 * Walk every type in the first container and try to find a match in the second.
707 * If there is a match, then update both the forward and reverse mapping tables.
709 * The self variable tells us whether or not we should be comparing the input
710 * ctf container with itself or not.
713 ctf_diff_pass1(ctf_diff_t
*cds
, boolean_t self
)
716 int istart
, iend
, jstart
, jend
;
718 if (cds
->cds_ifp
->ctf_flags
& LCTF_CHILD
) {
720 iend
= cds
->cds_ifp
->ctf_typemax
+ 0x8000;
723 iend
= cds
->cds_ifp
->ctf_typemax
;
726 if (cds
->cds_ofp
->ctf_flags
& LCTF_CHILD
) {
728 jend
= cds
->cds_ofp
->ctf_typemax
+ 0x8000;
731 jend
= cds
->cds_ofp
->ctf_typemax
;
734 for (i
= istart
; i
<= iend
; i
++) {
738 * If we're doing a self diff for dedup purposes, then we want
739 * to ensure that we compare a type i with every type in the
740 * range, [ 1, i ). Yes, this does mean that when i equals 1,
741 * we won't compare anything.
743 if (self
== B_TRUE
) {
747 for (j
= jstart
; j
<= jend
; j
++) {
748 ctf_diff_guess_t
*cdg
, *tofree
;
750 ASSERT(cds
->cds_guess
== NULL
);
751 diff
= ctf_diff_type(cds
, cds
->cds_ifp
, i
,
756 /* Clean up our guesses */
757 cdg
= cds
->cds_guess
;
758 cds
->cds_guess
= NULL
;
759 while (cdg
!= NULL
) {
760 if (diff
== B_TRUE
) {
761 cds
->cds_forward
[TINDEX(cdg
->cdg_iid
)] =
763 cds
->cds_reverse
[TINDEX(cdg
->cdg_oid
)] =
768 ctf_free(tofree
, sizeof (ctf_diff_guess_t
));
771 /* Found a hit, update the tables */
772 if (diff
== B_FALSE
) {
773 cds
->cds_forward
[TINDEX(i
)] = j
;
774 if (cds
->cds_reverse
[TINDEX(j
)] == 0)
775 cds
->cds_reverse
[TINDEX(j
)] = i
;
780 /* Call the callback at this point */
781 if (diff
== B_TRUE
) {
782 cds
->cds_forward
[TINDEX(i
)] = CTF_ERR
;
783 cds
->cds_func(cds
->cds_ifp
, i
, B_FALSE
, NULL
, CTF_ERR
,
786 cds
->cds_func(cds
->cds_ifp
, i
, B_TRUE
, cds
->cds_ofp
, j
,
795 * Now we need to walk the second container and emit anything that we didn't
796 * find as common in the first pass.
799 ctf_diff_pass2(ctf_diff_t
*cds
)
804 end
= cds
->cds_ofp
->ctf_typemax
;
805 if (cds
->cds_ofp
->ctf_flags
& LCTF_CHILD
) {
810 for (i
= start
; i
<= end
; i
++) {
811 if (cds
->cds_reverse
[TINDEX(i
)] != 0)
813 cds
->cds_func(cds
->cds_ofp
, i
, B_FALSE
, NULL
, CTF_ERR
,
821 ctf_diff_init(ctf_file_t
*ifp
, ctf_file_t
*ofp
, ctf_diff_t
**cdsp
)
826 cds
= ctf_alloc(sizeof (ctf_diff_t
));
828 return (ctf_set_errno(ifp
, ENOMEM
));
830 bzero(cds
, sizeof (ctf_diff_t
));
834 fsize
= sizeof (ctf_id_t
) * ifp
->ctf_typemax
;
835 rsize
= sizeof (ctf_id_t
) * ofp
->ctf_typemax
;
836 if (ifp
->ctf_flags
& LCTF_CHILD
)
837 fsize
+= 0x8000 * sizeof (ctf_id_t
);
838 if (ofp
->ctf_flags
& LCTF_CHILD
)
839 rsize
+= 0x8000 * sizeof (ctf_id_t
);
841 cds
->cds_forward
= ctf_alloc(fsize
);
842 if (cds
->cds_forward
== NULL
) {
843 ctf_free(cds
, sizeof (ctf_diff_t
));
844 return (ctf_set_errno(ifp
, ENOMEM
));
846 cds
->cds_fsize
= fsize
;
847 cds
->cds_reverse
= ctf_alloc(rsize
);
848 if (cds
->cds_reverse
== NULL
) {
849 ctf_free(cds
->cds_forward
, fsize
);
850 ctf_free(cds
, sizeof (ctf_diff_t
));
851 return (ctf_set_errno(ifp
, ENOMEM
));
853 cds
->cds_rsize
= rsize
;
854 bzero(cds
->cds_forward
, fsize
);
855 bzero(cds
->cds_reverse
, rsize
);
857 cds
->cds_ifp
->ctf_refcnt
++;
858 cds
->cds_ofp
->ctf_refcnt
++;
864 ctf_diff_types(ctf_diff_t
*cds
, ctf_diff_type_f cb
, void *arg
)
871 ret
= ctf_diff_pass1(cds
, B_FALSE
);
873 ret
= ctf_diff_pass2(cds
);
875 cds
->cds_func
= NULL
;
877 cds
->cds_tvalid
= B_TRUE
;
882 * Do a diff where we're comparing a container with itself. In other words we'd
883 * like to know what types are actually duplicates of existing types in the
886 * Note this should remain private to libctf and not be exported in the public
887 * mapfile for the time being.
890 ctf_diff_self(ctf_diff_t
*cds
, ctf_diff_type_f cb
, void *arg
)
892 if (cds
->cds_ifp
!= cds
->cds_ofp
)
898 return (ctf_diff_pass1(cds
, B_TRUE
));
903 ctf_diff_fini(ctf_diff_t
*cds
)
905 ctf_diff_guess_t
*cdg
;
911 cds
->cds_ifp
->ctf_refcnt
--;
912 cds
->cds_ofp
->ctf_refcnt
--;
914 fsize
= sizeof (ctf_id_t
) * cds
->cds_ifp
->ctf_typemax
;
915 rsize
= sizeof (ctf_id_t
) * cds
->cds_ofp
->ctf_typemax
;
916 if (cds
->cds_ifp
->ctf_flags
& LCTF_CHILD
)
917 fsize
+= 0x8000 * sizeof (ctf_id_t
);
918 if (cds
->cds_ofp
->ctf_flags
& LCTF_CHILD
)
919 rsize
+= 0x8000 * sizeof (ctf_id_t
);
921 if (cds
->cds_ifuncs
!= NULL
)
922 ctf_free(cds
->cds_ifuncs
,
923 sizeof (ctf_diff_func_t
) * cds
->cds_nifuncs
);
924 if (cds
->cds_ofuncs
!= NULL
)
925 ctf_free(cds
->cds_ofuncs
,
926 sizeof (ctf_diff_func_t
) * cds
->cds_nofuncs
);
927 if (cds
->cds_iobj
!= NULL
)
928 ctf_free(cds
->cds_iobj
,
929 sizeof (ctf_diff_obj_t
) * cds
->cds_niobj
);
930 if (cds
->cds_oobj
!= NULL
)
931 ctf_free(cds
->cds_oobj
,
932 sizeof (ctf_diff_obj_t
) * cds
->cds_noobj
);
933 cdg
= cds
->cds_guess
;
934 while (cdg
!= NULL
) {
935 ctf_diff_guess_t
*tofree
= cdg
;
937 ctf_free(tofree
, sizeof (ctf_diff_guess_t
));
939 if (cds
->cds_forward
!= NULL
)
940 ctf_free(cds
->cds_forward
, cds
->cds_fsize
);
941 if (cds
->cds_reverse
!= NULL
)
942 ctf_free(cds
->cds_reverse
, cds
->cds_rsize
);
943 ctf_free(cds
, sizeof (ctf_diff_t
));
947 ctf_diff_getflags(ctf_diff_t
*cds
)
949 return (cds
->cds_flags
);
953 ctf_diff_setflags(ctf_diff_t
*cds
, uint_t flags
)
955 if ((flags
& ~CTF_DIFF_F_IGNORE_INTNAMES
) != 0)
956 return (ctf_set_errno(cds
->cds_ifp
, EINVAL
));
958 cds
->cds_flags
= flags
;
963 ctf_diff_symid(ctf_diff_t
*cds
, ctf_id_t iid
, ctf_id_t oid
)
965 ctf_file_t
*ifp
, *ofp
;
971 * If we have parent containers on the scene here, we need to go through
972 * and do a full diff check because while a diff for types will not
973 * actually go through and check types in the parent container.
975 if (iid
== 0 || oid
== 0)
976 return (iid
== oid
? B_FALSE
: B_TRUE
);
978 if (!(ifp
->ctf_flags
& LCTF_CHILD
) && !(ofp
->ctf_flags
& LCTF_CHILD
)) {
979 if (cds
->cds_forward
[TINDEX(iid
)] != oid
)
984 return (ctf_diff_type(cds
, ifp
, iid
, ofp
, oid
));
989 ctf_diff_void_cb(ctf_file_t
*ifp
, ctf_id_t iid
, boolean_t same
, ctf_file_t
*ofp
,
990 ctf_id_t oid
, void *arg
)
996 ctf_diff_func_count(const char *name
, ulong_t symidx
, ctf_funcinfo_t
*fip
,
1007 ctf_diff_func_fill_cb(const char *name
, ulong_t symidx
, ctf_funcinfo_t
*fip
,
1011 ctf_diff_func_t
*funcptr
;
1012 ctf_diff_t
*cds
= arg
;
1014 if (cds
->cds_ffillip
== B_TRUE
) {
1015 max
= cds
->cds_nifuncs
;
1016 next
= &cds
->cds_nextifunc
;
1017 funcptr
= cds
->cds_ifuncs
+ *next
;
1019 max
= cds
->cds_nofuncs
;
1020 next
= &cds
->cds_nextofunc
;
1021 funcptr
= cds
->cds_ofuncs
+ *next
;
1025 VERIFY(*next
< max
);
1026 funcptr
->cdf_name
= name
;
1027 funcptr
->cdf_symidx
= symidx
;
1028 funcptr
->cdf_matchidx
= ULONG_MAX
;
1035 ctf_diff_func_fill(ctf_diff_t
*cds
)
1038 uint32_t ifcount
, ofcount
, idcnt
, cti
;
1040 ctf_id_t
*iids
, *oids
;
1048 ret
= ctf_function_iter(cds
->cds_ifp
, ctf_diff_func_count
, &ifcount
);
1051 ret
= ctf_function_iter(cds
->cds_ofp
, ctf_diff_func_count
, &ofcount
);
1055 cds
->cds_ifuncs
= ctf_alloc(sizeof (ctf_diff_func_t
) * ifcount
);
1056 if (cds
->cds_ifuncs
== NULL
)
1057 return (ctf_set_errno(cds
->cds_ifp
, ENOMEM
));
1059 cds
->cds_nifuncs
= ifcount
;
1060 cds
->cds_nextifunc
= 0;
1062 cds
->cds_ofuncs
= ctf_alloc(sizeof (ctf_diff_func_t
) * ofcount
);
1063 if (cds
->cds_ofuncs
== NULL
)
1064 return (ctf_set_errno(cds
->cds_ifp
, ENOMEM
));
1066 cds
->cds_nofuncs
= ofcount
;
1067 cds
->cds_nextofunc
= 0;
1069 cds
->cds_ffillip
= B_TRUE
;
1070 if ((ret
= ctf_function_iter(cds
->cds_ifp
, ctf_diff_func_fill_cb
,
1074 cds
->cds_ffillip
= B_FALSE
;
1075 if ((ret
= ctf_function_iter(cds
->cds_ofp
, ctf_diff_func_fill_cb
,
1080 * Everything is initialized to not match. This could probably be faster
1081 * with something that used a hash. But this part of the diff isn't used
1084 for (i
= 0; i
< cds
->cds_nifuncs
; i
++) {
1085 for (j
= 0; j
< cds
->cds_nofuncs
; j
++) {
1086 ctf_diff_func_t
*ifd
, *ofd
;
1087 ctf_funcinfo_t ifip
, ofip
;
1090 ifd
= &cds
->cds_ifuncs
[i
];
1091 ofd
= &cds
->cds_ofuncs
[j
];
1092 if (strcmp(ifd
->cdf_name
, ofd
->cdf_name
) != 0)
1095 ret
= ctf_func_info(cds
->cds_ifp
, ifd
->cdf_symidx
,
1099 ret
= ctf_func_info(cds
->cds_ofp
, ofd
->cdf_symidx
,
1102 ret
= ctf_set_errno(cds
->cds_ifp
,
1103 ctf_errno(cds
->cds_ofp
));
1107 if (ifip
.ctc_argc
!= ofip
.ctc_argc
&&
1108 ifip
.ctc_flags
!= ofip
.ctc_flags
)
1111 /* Validate return type and arguments are the same */
1112 if (ctf_diff_symid(cds
, ifip
.ctc_return
,
1116 if (ifip
.ctc_argc
> idcnt
) {
1119 sizeof (ctf_id_t
) * idcnt
);
1122 sizeof (ctf_id_t
) * idcnt
);
1124 idcnt
= ifip
.ctc_argc
;
1125 iids
= ctf_alloc(sizeof (ctf_id_t
) * idcnt
);
1127 ret
= ctf_set_errno(cds
->cds_ifp
,
1131 oids
= ctf_alloc(sizeof (ctf_id_t
) * idcnt
);
1133 ret
= ctf_set_errno(cds
->cds_ifp
,
1139 if ((ret
= ctf_func_args(cds
->cds_ifp
, ifd
->cdf_symidx
,
1140 ifip
.ctc_argc
, iids
)) != 0)
1142 if ((ret
= ctf_func_args(cds
->cds_ofp
, ofd
->cdf_symidx
,
1143 ofip
.ctc_argc
, oids
)) != 0)
1147 for (cti
= 0; cti
< ifip
.ctc_argc
; cti
++) {
1148 if (ctf_diff_symid(cds
, iids
[cti
], oids
[cti
])) {
1154 if (match
== B_FALSE
)
1157 ifd
->cdf_matchidx
= j
;
1158 ofd
->cdf_matchidx
= i
;
1167 ctf_free(iids
, sizeof (ctf_id_t
) * idcnt
);
1169 ctf_free(oids
, sizeof (ctf_id_t
) * idcnt
);
1175 * In general, two functions are the same, if they have the same name and their
1176 * arguments have the same types, including the return type. Like types, we
1177 * basically have to do this in two passes. In the first phase we walk every
1178 * type in the first container and try to find a match in the second.
1181 ctf_diff_functions(ctf_diff_t
*cds
, ctf_diff_func_f cb
, void *arg
)
1186 if (cds
->cds_tvalid
== B_FALSE
) {
1187 if ((ret
= ctf_diff_types(cds
, ctf_diff_void_cb
, NULL
)) != 0)
1191 if (cds
->cds_fvalid
== B_FALSE
) {
1192 if ((ret
= ctf_diff_func_fill(cds
)) != 0)
1194 cds
->cds_fvalid
= B_TRUE
;
1197 for (i
= 0; i
< cds
->cds_nifuncs
; i
++) {
1198 if (cds
->cds_ifuncs
[i
].cdf_matchidx
== ULONG_MAX
) {
1199 cb(cds
->cds_ifp
, cds
->cds_ifuncs
[i
].cdf_symidx
,
1200 B_FALSE
, NULL
, ULONG_MAX
, arg
);
1202 ulong_t idx
= cds
->cds_ifuncs
[i
].cdf_matchidx
;
1203 cb(cds
->cds_ifp
, cds
->cds_ifuncs
[i
].cdf_symidx
, B_TRUE
,
1204 cds
->cds_ofp
, cds
->cds_ofuncs
[idx
].cdf_symidx
, arg
);
1208 for (i
= 0; i
< cds
->cds_nofuncs
; i
++) {
1209 if (cds
->cds_ofuncs
[i
].cdf_matchidx
!= ULONG_MAX
)
1211 cb(cds
->cds_ofp
, cds
->cds_ofuncs
[i
].cdf_symidx
, B_FALSE
,
1212 NULL
, ULONG_MAX
, arg
);
1219 ctf_diff_obj_fill_cb(const char *name
, ctf_id_t id
, ulong_t symidx
, void *arg
)
1222 ctf_diff_obj_t
*objptr
;
1223 ctf_diff_t
*cds
= arg
;
1225 if (cds
->cds_ofillip
== B_TRUE
) {
1226 max
= cds
->cds_niobj
;
1227 next
= &cds
->cds_nextiobj
;
1228 objptr
= cds
->cds_iobj
+ *next
;
1230 max
= cds
->cds_noobj
;
1231 next
= &cds
->cds_nextoobj
;
1232 objptr
= cds
->cds_oobj
+ *next
;
1236 VERIFY(*next
< max
);
1237 objptr
->cdo_name
= name
;
1238 objptr
->cdo_symidx
= symidx
;
1239 objptr
->cdo_id
= id
;
1240 objptr
->cdo_matchidx
= ULONG_MAX
;
1248 ctf_diff_obj_count(const char *name
, ctf_id_t id
, ulong_t symidx
, void *arg
)
1250 uint32_t *count
= arg
;
1252 *count
= *count
+ 1;
1259 ctf_diff_obj_fill(ctf_diff_t
*cds
)
1262 uint32_t iocount
, oocount
;
1268 ret
= ctf_object_iter(cds
->cds_ifp
, ctf_diff_obj_count
, &iocount
);
1272 ret
= ctf_object_iter(cds
->cds_ofp
, ctf_diff_obj_count
, &oocount
);
1276 cds
->cds_iobj
= ctf_alloc(sizeof (ctf_diff_obj_t
) * iocount
);
1277 if (cds
->cds_iobj
== NULL
)
1278 return (ctf_set_errno(cds
->cds_ifp
, ENOMEM
));
1279 cds
->cds_niobj
= iocount
;
1280 cds
->cds_nextiobj
= 0;
1282 cds
->cds_oobj
= ctf_alloc(sizeof (ctf_diff_obj_t
) * oocount
);
1283 if (cds
->cds_oobj
== NULL
)
1284 return (ctf_set_errno(cds
->cds_ifp
, ENOMEM
));
1285 cds
->cds_noobj
= oocount
;
1286 cds
->cds_nextoobj
= 0;
1288 cds
->cds_ofillip
= B_TRUE
;
1289 if ((ret
= ctf_object_iter(cds
->cds_ifp
, ctf_diff_obj_fill_cb
,
1293 cds
->cds_ofillip
= B_FALSE
;
1294 if ((ret
= ctf_object_iter(cds
->cds_ofp
, ctf_diff_obj_fill_cb
,
1298 for (i
= 0; i
< cds
->cds_niobj
; i
++) {
1299 for (j
= 0; j
< cds
->cds_noobj
; j
++) {
1300 ctf_diff_obj_t
*id
, *od
;
1302 id
= &cds
->cds_iobj
[i
];
1303 od
= &cds
->cds_oobj
[j
];
1305 if (id
->cdo_name
== NULL
|| od
->cdo_name
== NULL
)
1307 if (strcmp(id
->cdo_name
, od
->cdo_name
) != 0)
1310 if (ctf_diff_symid(cds
, id
->cdo_id
, od
->cdo_id
)) {
1314 id
->cdo_matchidx
= j
;
1315 od
->cdo_matchidx
= i
;
1324 ctf_diff_objects(ctf_diff_t
*cds
, ctf_diff_obj_f cb
, void *arg
)
1329 if (cds
->cds_tvalid
== B_FALSE
) {
1330 if ((ret
= ctf_diff_types(cds
, ctf_diff_void_cb
, NULL
)) != 0)
1334 if (cds
->cds_ovalid
== B_FALSE
) {
1335 if ((ret
= ctf_diff_obj_fill(cds
)) != 0)
1337 cds
->cds_ovalid
= B_TRUE
;
1340 for (i
= 0; i
< cds
->cds_niobj
; i
++) {
1341 ctf_diff_obj_t
*o
= &cds
->cds_iobj
[i
];
1343 if (cds
->cds_iobj
[i
].cdo_matchidx
== ULONG_MAX
) {
1344 cb(cds
->cds_ifp
, o
->cdo_symidx
, o
->cdo_id
, B_FALSE
,
1345 NULL
, ULONG_MAX
, CTF_ERR
, arg
);
1347 ctf_diff_obj_t
*alt
= &cds
->cds_oobj
[o
->cdo_matchidx
];
1348 cb(cds
->cds_ifp
, o
->cdo_symidx
, o
->cdo_id
, B_TRUE
,
1349 cds
->cds_ofp
, alt
->cdo_symidx
, alt
->cdo_id
, arg
);
1353 for (i
= 0; i
< cds
->cds_noobj
; i
++) {
1354 ctf_diff_obj_t
*o
= &cds
->cds_oobj
[i
];
1355 if (o
->cdo_matchidx
!= ULONG_MAX
)
1357 cb(cds
->cds_ofp
, o
->cdo_symidx
, o
->cdo_id
, B_FALSE
, NULL
,
1358 ULONG_MAX
, CTF_ERR
, arg
);