1 /* 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 5 * 1.0 of the CDDL. 6 * 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. 10 */ 11 12 /* 13 * Copyright (c) 2015 Joyent, Inc. All rights reserved. 14 */ 15 16 /* 17 * The following is 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. 22 * 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: 29 * 30 * struct foo { 31 * struct foo *foo_next; 32 * }; 33 * 34 * If it turns out that we were wrong, we discard our guesses. 35 * 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. 42 */ 43 44 #include <libctf.h> 45 #include <ctf_impl.h> 46 #include <sys/debug.h> 47 48 typedef struct ctf_diff_func { 49 const char *cdf_name; 50 ulong_t cdf_symidx; 51 ulong_t cdf_matchidx; 52 } ctf_diff_func_t; 53 54 typedef struct ctf_diff_obj { 55 const char *cdo_name; 56 ulong_t cdo_symidx; 57 ctf_id_t cdo_id; 58 ulong_t cdo_matchidx; 59 } ctf_diff_obj_t; 60 61 typedef struct ctf_diff_guess { 62 struct ctf_diff_guess *cdg_next; 63 ctf_id_t cdg_iid; 64 ctf_id_t cdg_oid; 65 } ctf_diff_guess_t; 66 67 /* typedef in libctf.h */ 68 struct ctf_diff { 69 uint_t cds_flags; 70 boolean_t cds_tvalid; /* types valid */ 71 ctf_file_t *cds_ifp; 72 ctf_file_t *cds_ofp; 73 ctf_id_t *cds_forward; 74 ctf_id_t *cds_reverse; 75 size_t cds_fsize; 76 size_t cds_rsize; 77 ctf_diff_type_f cds_func; 78 ctf_diff_guess_t *cds_guess; 79 void *cds_arg; 80 uint_t cds_nifuncs; 81 uint_t cds_nofuncs; 82 uint_t cds_nextifunc; 83 uint_t cds_nextofunc; 84 ctf_diff_func_t *cds_ifuncs; 85 ctf_diff_func_t *cds_ofuncs; 86 boolean_t cds_ffillip; 87 boolean_t cds_fvalid; 88 uint_t cds_niobj; 89 uint_t cds_noobj; 90 uint_t cds_nextiobj; 91 uint_t cds_nextoobj; 92 ctf_diff_obj_t *cds_iobj; 93 ctf_diff_obj_t *cds_oobj; 94 boolean_t cds_ofillip; 95 boolean_t cds_ovalid; 96 }; 97 98 #define TINDEX(tid) (tid - 1) 99 100 /* 101 * Team Diff 102 */ 103 static int ctf_diff_type(ctf_diff_t *, ctf_file_t *, ctf_id_t, ctf_file_t *, 104 ctf_id_t); 105 106 static int 107 ctf_diff_name(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid) 108 { 109 const char *iname, *oname; 110 const ctf_type_t *itp, *otp; 111 112 if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL) 113 return (CTF_ERR); 114 115 if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL) 116 return (ctf_set_errno(ifp, iid)); 117 118 iname = ctf_strptr(ifp, itp->ctt_name); 119 oname = ctf_strptr(ofp, otp->ctt_name); 120 121 if ((iname == NULL || oname == NULL) && (iname != oname)) 122 return (B_TRUE); 123 124 /* Two anonymous names are the same */ 125 if (iname == NULL && oname == NULL) 126 return (B_FALSE); 127 128 return (strcmp(iname, oname) == 0 ? B_FALSE: B_TRUE); 129 } 130 131 /* 132 * For floats and ints 133 */ 134 static int 135 ctf_diff_number(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid) 136 { 137 ctf_encoding_t ien, den; 138 139 if (ctf_type_encoding(ifp, iid, &ien) != 0) 140 return (CTF_ERR); 141 142 if (ctf_type_encoding(ofp, oid, &den) != 0) 143 return (ctf_set_errno(ifp, iid)); 144 145 if (bcmp(&ien, &den, sizeof (ctf_encoding_t)) != 0) 146 return (B_TRUE); 147 148 return (B_FALSE); 149 } 150 151 /* 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: 154 * 155 * size_t -> ulong_t -> unsigned long 156 * size_t -> unsigned long 157 * 158 * That we'll ultimately end up treating them the same. 159 */ 160 static int 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) 163 { 164 ctf_id_t iref = CTF_ERR, oref = CTF_ERR; 165 166 while (ctf_type_kind(ifp, iid) == CTF_K_TYPEDEF) { 167 iref = ctf_type_reference(ifp, iid); 168 if (iref == CTF_ERR) 169 return (CTF_ERR); 170 iid = iref; 171 } 172 173 while (ctf_type_kind(ofp, oid) == CTF_K_TYPEDEF) { 174 oref = ctf_type_reference(ofp, oid); 175 if (oref == CTF_ERR) 176 return (CTF_ERR); 177 oid = oref; 178 } 179 180 VERIFY(iref != CTF_ERR && oref != CTF_ERR); 181 return (ctf_diff_type(cds, ifp, iref, ofp, oref)); 182 } 183 184 /* 185 * Two qualifiers are equivalent iff they point to two equivalent types. 186 */ 187 static int 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) 190 { 191 ctf_id_t iref, oref; 192 193 iref = ctf_type_reference(ifp, iid); 194 if (iref == CTF_ERR) 195 return (CTF_ERR); 196 197 oref = ctf_type_reference(ofp, oid); 198 if (oref == CTF_ERR) 199 return (ctf_set_errno(ifp, ctf_errno(ofp))); 200 201 return (ctf_diff_type(cds, ifp, iref, ofp, oref)); 202 } 203 204 /* 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. 207 */ 208 static int 209 ctf_diff_array(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, 210 ctf_id_t oid) 211 { 212 int ret; 213 ctf_arinfo_t iar, oar; 214 215 if (ctf_array_info(ifp, iid, &iar) == CTF_ERR) 216 return (CTF_ERR); 217 218 if (ctf_array_info(ofp, oid, &oar) == CTF_ERR) 219 return (ctf_set_errno(ifp, ctf_errno(ofp))); 220 221 ret = ctf_diff_type(cds, ifp, iar.ctr_contents, ofp, oar.ctr_contents); 222 if (ret != B_FALSE) 223 return (ret); 224 225 if (iar.ctr_nelems != oar.ctr_nelems) 226 return (B_TRUE); 227 228 /* 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. 233 */ 234 if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0) { 235 ret = ctf_diff_type(cds, ifp, iar.ctr_index, ofp, 236 oar.ctr_index); 237 if (ret != B_FALSE) 238 return (ret); 239 } 240 241 return (B_FALSE); 242 } 243 244 /* 245 * Two function pointers are the same if the following is all true: 246 * 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 251 */ 252 static int 253 ctf_diff_fptr(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, 254 ctf_id_t oid) 255 { 256 int ret, i; 257 ctf_funcinfo_t ifunc, ofunc; 258 ctf_id_t *iids, *oids; 259 260 if (ctf_func_info_by_id(ifp, iid, &ifunc) == CTF_ERR) 261 return (CTF_ERR); 262 263 if (ctf_func_info_by_id(ofp, oid, &ofunc) == CTF_ERR) 264 return (ctf_set_errno(ifp, ctf_errno(ofp))); 265 266 if (ifunc.ctc_argc != ofunc.ctc_argc) 267 return (B_TRUE); 268 269 if (ifunc.ctc_flags != ofunc.ctc_flags) 270 return (B_TRUE); 271 272 ret = ctf_diff_type(cds, ifp, ifunc.ctc_return, ofp, ofunc.ctc_return); 273 if (ret != B_FALSE) 274 return (ret); 275 276 iids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc); 277 if (iids == NULL) 278 return (ctf_set_errno(ifp, ENOMEM)); 279 280 oids = ctf_alloc(sizeof (ctf_id_t) * ifunc.ctc_argc); 281 if (oids == NULL) { 282 ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc); 283 return (ctf_set_errno(ifp, ENOMEM)); 284 } 285 286 if (ctf_func_args_by_id(ifp, iid, ifunc.ctc_argc, iids) == CTF_ERR) { 287 ret = CTF_ERR; 288 goto out; 289 } 290 291 if (ctf_func_args_by_id(ofp, oid, ofunc.ctc_argc, oids) == CTF_ERR) { 292 ret = ctf_set_errno(ifp, ctf_errno(ofp)); 293 goto out; 294 } 295 296 ret = B_TRUE; 297 for (i = 0; i < ifunc.ctc_argc; i++) { 298 ret = ctf_diff_type(cds, ifp, iids[i], ofp, oids[i]); 299 if (ret != B_FALSE) 300 goto out; 301 } 302 ret = B_FALSE; 303 304 out: 305 ctf_free(iids, sizeof (ctf_id_t) * ifunc.ctc_argc); 306 ctf_free(oids, sizeof (ctf_id_t) * ofunc.ctc_argc); 307 return (ret); 308 } 309 310 /* 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 313 * same overall size. 314 */ 315 static int 316 ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, 317 ctf_id_t oid) 318 { 319 ctf_file_t *oifp; 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; 324 int n; 325 ctf_diff_guess_t *cdg; 326 327 oifp = ifp; 328 329 if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL) 330 return (CTF_ERR); 331 332 if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL) 333 return (ctf_set_errno(oifp, ctf_errno(ofp))); 334 335 if (ctf_type_size(ifp, iid) != ctf_type_size(ofp, oid)) 336 return (B_TRUE); 337 338 if (LCTF_INFO_VLEN(ifp, itp->ctt_info) != 339 LCTF_INFO_VLEN(ofp, otp->ctt_info)) 340 return (B_TRUE); 341 342 (void) ctf_get_ctt_size(ifp, itp, &isize, &iincr); 343 (void) ctf_get_ctt_size(ofp, otp, &osize, &oincr); 344 345 if (ifp->ctf_version == CTF_VERSION_1 || isize < CTF_LSTRUCT_THRESH) { 346 imp = (const ctf_member_t *)((uintptr_t)itp + iincr); 347 ilmp = NULL; 348 } else { 349 imp = NULL; 350 ilmp = (const ctf_lmember_t *)((uintptr_t)itp + iincr); 351 } 352 353 if (ofp->ctf_version == CTF_VERSION_1 || osize < CTF_LSTRUCT_THRESH) { 354 omp = (const ctf_member_t *)((uintptr_t)otp + oincr); 355 olmp = NULL; 356 } else { 357 omp = NULL; 358 olmp = (const ctf_lmember_t *)((uintptr_t)otp + oincr); 359 } 360 361 /* 362 * Insert our assumption that they're equal for the moment. 363 */ 364 cdg = ctf_alloc(sizeof (ctf_diff_guess_t)); 365 if (cdg == NULL) 366 return (ctf_set_errno(ifp, ENOMEM)); 367 cdg->cdg_iid = iid; 368 cdg->cdg_oid = oid; 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; 373 374 for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0; n--) { 375 const char *iname, *oname; 376 ulong_t ioff, ooff; 377 ctf_id_t itype, otype; 378 int ret; 379 380 if (imp != NULL) { 381 iname = ctf_strptr(ifp, imp->ctm_name); 382 ioff = imp->ctm_offset; 383 itype = imp->ctm_type; 384 } else { 385 iname = ctf_strptr(ifp, ilmp->ctlm_name); 386 ioff = CTF_LMEM_OFFSET(ilmp); 387 itype = ilmp->ctlm_type; 388 } 389 390 if (omp != NULL) { 391 oname = ctf_strptr(ofp, omp->ctm_name); 392 ooff = omp->ctm_offset; 393 otype = omp->ctm_type; 394 } else { 395 oname = ctf_strptr(ofp, olmp->ctlm_name); 396 ooff = CTF_LMEM_OFFSET(olmp); 397 otype = olmp->ctlm_type; 398 } 399 400 if (ioff != ooff) { 401 return (B_TRUE); 402 } 403 if (strcmp(iname, oname) != 0) { 404 return (B_TRUE); 405 } 406 ret = ctf_diff_type(cds, ifp, itype, ofp, otype); 407 if (ret != B_FALSE) { 408 return (ret); 409 } 410 411 /* Advance our pointers */ 412 if (imp != NULL) 413 imp++; 414 if (ilmp != NULL) 415 ilmp++; 416 if (omp != NULL) 417 omp++; 418 if (olmp != NULL) 419 olmp++; 420 } 421 422 return (B_FALSE); 423 } 424 425 /* 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, there is no guarantee of ordering so we have to fall back to 429 * doing an O(N^2) scan. 430 */ 431 typedef struct ctf_diff_union_member { 432 ctf_diff_t *cdum_cds; 433 ctf_file_t *cdum_fp; 434 ctf_file_t *cdum_iterfp; 435 const char *cdum_name; 436 ctf_id_t cdum_type; 437 int cdum_ret; 438 } ctf_diff_union_member_t; 439 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; 444 ctf_id_t cduf_type; 445 int cduf_ret; 446 } ctf_diff_union_fp_t; 447 448 /* ARGSUSED */ 449 static int 450 ctf_diff_union_check_member(const char *name, ctf_id_t id, ulong_t off, 451 void *arg) 452 { 453 int ret; 454 ctf_diff_union_member_t *cdump = arg; 455 456 if (strcmp(name, cdump->cdum_name) != 0) 457 return (0); 458 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; 463 return (1); 464 } 465 466 if (ret == B_FALSE) { 467 cdump->cdum_ret = B_FALSE; 468 /* Return non-zero to stop iteration as we have a match */ 469 return (1); 470 } 471 472 return (0); 473 } 474 475 /* ARGSUSED */ 476 static int 477 ctf_diff_union_check_fp(const char *name, ctf_id_t id, ulong_t off, void *arg) 478 { 479 int ret; 480 ctf_diff_union_member_t cdum; 481 ctf_diff_union_fp_t *cdufp = arg; 482 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; 487 cdum.cdum_type = id; 488 cdum.cdum_ret = B_TRUE; 489 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; 495 return (1); 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; 499 return (1); 500 } else { 501 ASSERT(cdum.cdum_ret == B_FALSE); 502 cdufp->cduf_ret = cdum.cdum_ret; 503 return (0); 504 } 505 } 506 507 static int 508 ctf_diff_union(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, 509 ctf_id_t oid) 510 { 511 ctf_file_t *oifp; 512 const ctf_type_t *itp, *otp; 513 ctf_diff_union_fp_t cduf; 514 ctf_diff_guess_t *cdg; 515 int ret; 516 517 oifp = ifp; 518 if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL) 519 return (CTF_ERR); 520 if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL) 521 return (ctf_set_errno(oifp, ctf_errno(ofp))); 522 523 if (LCTF_INFO_VLEN(ifp, itp->ctt_info) != 524 LCTF_INFO_VLEN(ofp, otp->ctt_info)) 525 return (B_TRUE); 526 527 cdg = ctf_alloc(sizeof (ctf_diff_guess_t)); 528 if (cdg == NULL) 529 return (ctf_set_errno(ifp, ENOMEM)); 530 cdg->cdg_iid = iid; 531 cdg->cdg_oid = oid; 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; 536 537 cduf.cduf_cds = cds; 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); 543 if (ret != CTF_ERR) 544 ret = cduf.cduf_ret; 545 546 return (ret); 547 } 548 549 /* 550 * Two enums are equivalent if they share the same underlying type and they have 551 * the same set of members. 552 */ 553 static int 554 ctf_diff_enum(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid) 555 { 556 ctf_file_t *oifp; 557 const ctf_type_t *itp, *otp; 558 ssize_t iincr, oincr; 559 const ctf_enum_t *iep, *oep; 560 int n; 561 562 oifp = ifp; 563 if ((itp = ctf_lookup_by_id(&ifp, iid)) == NULL) 564 return (CTF_ERR); 565 if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL) 566 return (ctf_set_errno(oifp, ctf_errno(ofp))); 567 568 if (LCTF_INFO_VLEN(ifp, itp->ctt_info) != 569 LCTF_INFO_VLEN(ofp, otp->ctt_info)) 570 return (B_TRUE); 571 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); 576 577 for (n = LCTF_INFO_VLEN(ifp, itp->ctt_info); n != 0; 578 n--, iep++, oep++) { 579 if (strcmp(ctf_strptr(ifp, iep->cte_name), 580 ctf_strptr(ofp, oep->cte_name)) != 0) 581 return (B_TRUE); 582 583 if (iep->cte_value != oep->cte_value) 584 return (B_TRUE); 585 } 586 587 return (B_FALSE); 588 } 589 590 /* 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. 594 */ 595 static int 596 ctf_diff_forward(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid) 597 { 598 int ikind, okind; 599 600 ikind = ctf_type_kind(ifp, iid); 601 okind = ctf_type_kind(ofp, oid); 602 603 if (ikind == okind) { 604 ASSERT(ikind == CTF_K_FORWARD); 605 return (B_FALSE); 606 } else if (ikind == CTF_K_FORWARD) { 607 return (okind != CTF_K_UNION && okind != CTF_K_STRUCT); 608 } else { 609 return (ikind != CTF_K_UNION && ikind != CTF_K_STRUCT); 610 } 611 } 612 613 /* 614 * Are two types equivalent? 615 */ 616 int 617 ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, 618 ctf_id_t oid) 619 { 620 int ret, ikind, okind; 621 622 /* Do a quick short circuit */ 623 if (ifp == ofp && iid == oid) 624 return (B_FALSE); 625 626 /* 627 * Check if it's something we've already encountered in a forward 628 * reference or forward negative table. Also double check the reverse 629 * table. 630 */ 631 if (cds->cds_forward[TINDEX(iid)] == oid) 632 return (B_FALSE); 633 if (cds->cds_forward[TINDEX(iid)] != 0) 634 return (B_TRUE); 635 if (cds->cds_reverse[TINDEX(oid)] == iid) 636 return (B_FALSE); 637 if ((cds->cds_flags & CTF_DIFF_F_IGNORE_INTNAMES) == 0 && 638 cds->cds_reverse[TINDEX(oid)] != 0) 639 return (B_TRUE); 640 641 ikind = ctf_type_kind(ifp, iid); 642 okind = ctf_type_kind(ofp, oid); 643 644 if (ikind != okind && 645 ikind != CTF_K_FORWARD && okind != CTF_K_FORWARD) 646 return (B_TRUE); 647 648 /* Check names */ 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) 652 return (ret); 653 } 654 655 if (ikind == CTF_K_FORWARD || okind == CTF_K_FORWARD) 656 return (ctf_diff_forward(ifp, iid, ofp, oid)); 657 658 switch (ikind) { 659 case CTF_K_INTEGER: 660 case CTF_K_FLOAT: 661 ret = ctf_diff_number(ifp, iid, ofp, oid); 662 break; 663 case CTF_K_ARRAY: 664 ret = ctf_diff_array(cds, ifp, iid, ofp, oid); 665 break; 666 case CTF_K_FUNCTION: 667 ret = ctf_diff_fptr(cds, ifp, iid, ofp, oid); 668 break; 669 case CTF_K_STRUCT: 670 ret = ctf_diff_struct(cds, ifp, iid, ofp, oid); 671 break; 672 case CTF_K_UNION: 673 ret = ctf_diff_union(cds, ifp, iid, ofp, oid); 674 break; 675 case CTF_K_ENUM: 676 ret = ctf_diff_enum(ifp, iid, ofp, oid); 677 break; 678 case CTF_K_FORWARD: 679 ret = ctf_diff_forward(ifp, iid, ofp, oid); 680 break; 681 case CTF_K_TYPEDEF: 682 ret = ctf_diff_typedef(cds, ifp, iid, ofp, oid); 683 break; 684 case CTF_K_POINTER: 685 case CTF_K_VOLATILE: 686 case CTF_K_CONST: 687 case CTF_K_RESTRICT: 688 ret = ctf_diff_qualifier(cds, ifp, iid, ofp, oid); 689 break; 690 case CTF_K_UNKNOWN: 691 /* 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. 695 */ 696 ret = B_TRUE; 697 break; 698 default: 699 abort(); 700 } 701 702 return (ret); 703 } 704 705 /* 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. 708 * 709 * The self variable tells us whether or not we should be comparing the input 710 * ctf container with itself or not. 711 */ 712 static int 713 ctf_diff_pass1(ctf_diff_t *cds, boolean_t self) 714 { 715 int i, j, diff; 716 int istart, iend, jstart, jend; 717 718 istart = 1; 719 iend = cds->cds_ifp->ctf_typemax; 720 if (cds->cds_ifp->ctf_flags & LCTF_CHILD) { 721 istart += CTF_CHILD_START; 722 iend += CTF_CHILD_START; 723 } 724 725 jstart = 1; 726 jend = cds->cds_ofp->ctf_typemax; 727 if (cds->cds_ofp->ctf_flags & LCTF_CHILD) { 728 jstart += CTF_CHILD_START; 729 jend += CTF_CHILD_START; 730 } 731 732 for (i = istart; i <= iend; i++) { 733 diff = B_TRUE; 734 735 /* 736 * If we're doing a self diff for dedup purposes, then we want 737 * to ensure that we compare a type i with every type in the 738 * range, [ 1, i ). Yes, this does mean that when i equals 1, 739 * we won't compare anything. 740 */ 741 if (self == B_TRUE) { 742 jstart = istart; 743 jend = i - 1; 744 } 745 for (j = jstart; j <= jend; j++) { 746 ctf_diff_guess_t *cdg, *tofree; 747 748 ASSERT(cds->cds_guess == NULL); 749 diff = ctf_diff_type(cds, cds->cds_ifp, i, 750 cds->cds_ofp, j); 751 if (diff == CTF_ERR) 752 return (CTF_ERR); 753 754 /* Clean up our guesses */ 755 cdg = cds->cds_guess; 756 cds->cds_guess = NULL; 757 while (cdg != NULL) { 758 if (diff == B_TRUE) { 759 cds->cds_forward[TINDEX(cdg->cdg_iid)] = 760 0; 761 cds->cds_reverse[TINDEX(cdg->cdg_oid)] = 762 0; 763 } 764 tofree = cdg; 765 cdg = cdg->cdg_next; 766 ctf_free(tofree, sizeof (ctf_diff_guess_t)); 767 } 768 769 /* Found a hit, update the tables */ 770 if (diff == B_FALSE) { 771 cds->cds_forward[TINDEX(i)] = j; 772 if (cds->cds_reverse[TINDEX(j)] == 0) 773 cds->cds_reverse[TINDEX(j)] = i; 774 break; 775 } 776 } 777 778 /* Call the callback at this point */ 779 if (diff == B_TRUE) { 780 cds->cds_forward[TINDEX(i)] = CTF_ERR; 781 cds->cds_func(cds->cds_ifp, i, B_FALSE, NULL, CTF_ERR, 782 cds->cds_arg); 783 } else { 784 cds->cds_func(cds->cds_ifp, i, B_TRUE, cds->cds_ofp, j, 785 cds->cds_arg); 786 } 787 } 788 789 return (0); 790 } 791 792 /* 793 * Now we need to walk the second container and emit anything that we didn't 794 * find as common in the first pass. 795 */ 796 static int 797 ctf_diff_pass2(ctf_diff_t *cds) 798 { 799 int i, start, end; 800 801 start = 0x1; 802 end = cds->cds_ofp->ctf_typemax; 803 if (cds->cds_ofp->ctf_flags & LCTF_CHILD) { 804 start += CTF_CHILD_START; 805 end += CTF_CHILD_START; 806 } 807 808 for (i = start; i <= end; i++) { 809 if (cds->cds_reverse[TINDEX(i)] != 0) 810 continue; 811 cds->cds_func(cds->cds_ofp, i, B_FALSE, NULL, CTF_ERR, 812 cds->cds_arg); 813 } 814 815 return (0); 816 } 817 818 int 819 ctf_diff_init(ctf_file_t *ifp, ctf_file_t *ofp, ctf_diff_t **cdsp) 820 { 821 ctf_diff_t *cds; 822 size_t fsize, rsize; 823 824 cds = ctf_alloc(sizeof (ctf_diff_t)); 825 if (cds == NULL) 826 return (ctf_set_errno(ifp, ENOMEM)); 827 828 bzero(cds, sizeof (ctf_diff_t)); 829 cds->cds_ifp = ifp; 830 cds->cds_ofp = ofp; 831 832 fsize = sizeof (ctf_id_t) * ifp->ctf_typemax; 833 rsize = sizeof (ctf_id_t) * ofp->ctf_typemax; 834 if (ifp->ctf_flags & LCTF_CHILD) 835 fsize += CTF_CHILD_START * sizeof (ctf_id_t); 836 if (ofp->ctf_flags & LCTF_CHILD) 837 rsize += CTF_CHILD_START * sizeof (ctf_id_t); 838 839 cds->cds_forward = ctf_alloc(fsize); 840 if (cds->cds_forward == NULL) { 841 ctf_free(cds, sizeof (ctf_diff_t)); 842 return (ctf_set_errno(ifp, ENOMEM)); 843 } 844 cds->cds_fsize = fsize; 845 cds->cds_reverse = ctf_alloc(rsize); 846 if (cds->cds_reverse == NULL) { 847 ctf_free(cds->cds_forward, fsize); 848 ctf_free(cds, sizeof (ctf_diff_t)); 849 return (ctf_set_errno(ifp, ENOMEM)); 850 } 851 cds->cds_rsize = rsize; 852 bzero(cds->cds_forward, fsize); 853 bzero(cds->cds_reverse, rsize); 854 855 cds->cds_ifp->ctf_refcnt++; 856 cds->cds_ofp->ctf_refcnt++; 857 *cdsp = cds; 858 return (0); 859 } 860 861 int 862 ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg) 863 { 864 int ret; 865 866 cds->cds_func = cb; 867 cds->cds_arg = arg; 868 869 ret = ctf_diff_pass1(cds, B_FALSE); 870 if (ret == 0) 871 ret = ctf_diff_pass2(cds); 872 873 cds->cds_func = NULL; 874 cds->cds_arg = NULL; 875 cds->cds_tvalid = B_TRUE; 876 return (ret); 877 } 878 879 /* 880 * Do a diff where we're comparing a container with itself. In other words we'd 881 * like to know what types are actually duplicates of existing types in the 882 * container. 883 * 884 * Note this should remain private to libctf and not be exported in the public 885 * mapfile for the time being. 886 */ 887 int 888 ctf_diff_self(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg) 889 { 890 if (cds->cds_ifp != cds->cds_ofp) 891 return (EINVAL); 892 893 cds->cds_func = cb; 894 cds->cds_arg = arg; 895 896 return (ctf_diff_pass1(cds, B_TRUE)); 897 } 898 899 900 void 901 ctf_diff_fini(ctf_diff_t *cds) 902 { 903 ctf_diff_guess_t *cdg; 904 size_t fsize, rsize; 905 906 if (cds == NULL) 907 return; 908 909 cds->cds_ifp->ctf_refcnt--; 910 cds->cds_ofp->ctf_refcnt--; 911 912 fsize = sizeof (ctf_id_t) * cds->cds_ifp->ctf_typemax; 913 rsize = sizeof (ctf_id_t) * cds->cds_ofp->ctf_typemax; 914 if (cds->cds_ifp->ctf_flags & LCTF_CHILD) 915 fsize += CTF_CHILD_START * sizeof (ctf_id_t); 916 if (cds->cds_ofp->ctf_flags & LCTF_CHILD) 917 rsize += CTF_CHILD_START * sizeof (ctf_id_t); 918 919 if (cds->cds_ifuncs != NULL) 920 ctf_free(cds->cds_ifuncs, 921 sizeof (ctf_diff_func_t) * cds->cds_nifuncs); 922 if (cds->cds_ofuncs != NULL) 923 ctf_free(cds->cds_ofuncs, 924 sizeof (ctf_diff_func_t) * cds->cds_nofuncs); 925 if (cds->cds_iobj != NULL) 926 ctf_free(cds->cds_iobj, 927 sizeof (ctf_diff_obj_t) * cds->cds_niobj); 928 if (cds->cds_oobj != NULL) 929 ctf_free(cds->cds_oobj, 930 sizeof (ctf_diff_obj_t) * cds->cds_noobj); 931 cdg = cds->cds_guess; 932 while (cdg != NULL) { 933 ctf_diff_guess_t *tofree = cdg; 934 cdg = cdg->cdg_next; 935 ctf_free(tofree, sizeof (ctf_diff_guess_t)); 936 } 937 if (cds->cds_forward != NULL) 938 ctf_free(cds->cds_forward, cds->cds_fsize); 939 if (cds->cds_reverse != NULL) 940 ctf_free(cds->cds_reverse, cds->cds_rsize); 941 ctf_free(cds, sizeof (ctf_diff_t)); 942 } 943 944 uint_t 945 ctf_diff_getflags(ctf_diff_t *cds) 946 { 947 return (cds->cds_flags); 948 } 949 950 int 951 ctf_diff_setflags(ctf_diff_t *cds, uint_t flags) 952 { 953 if ((flags & ~CTF_DIFF_F_IGNORE_INTNAMES) != 0) 954 return (ctf_set_errno(cds->cds_ifp, EINVAL)); 955 956 cds->cds_flags = flags; 957 return (0); 958 } 959 960 static boolean_t 961 ctf_diff_symid(ctf_diff_t *cds, ctf_id_t iid, ctf_id_t oid) 962 { 963 ctf_file_t *ifp, *ofp; 964 965 ifp = cds->cds_ifp; 966 ofp = cds->cds_ofp; 967 968 /* 969 * If we have parent containers on the scene here, we need to go through 970 * and do a full diff check because a diff for types will not actually 971 * go through and check types in the parent container. 972 */ 973 if (iid == 0 || oid == 0) 974 return (iid == oid ? B_FALSE: B_TRUE); 975 976 if (!(ifp->ctf_flags & LCTF_CHILD) && !(ofp->ctf_flags & LCTF_CHILD)) { 977 if (cds->cds_forward[TINDEX(iid)] != oid) 978 return (B_TRUE); 979 return (B_FALSE); 980 } 981 982 return (ctf_diff_type(cds, ifp, iid, ofp, oid)); 983 } 984 985 /* ARGSUSED */ 986 static void 987 ctf_diff_void_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp, 988 ctf_id_t oid, void *arg) 989 { 990 } 991 992 /* ARGSUSED */ 993 static int 994 ctf_diff_func_count(const char *name, ulong_t symidx, ctf_funcinfo_t *fip, 995 void *arg) 996 { 997 uint32_t *ip = arg; 998 999 *ip = *ip + 1; 1000 return (0); 1001 } 1002 1003 /* ARGSUSED */ 1004 static int 1005 ctf_diff_func_fill_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *fip, 1006 void *arg) 1007 { 1008 uint_t *next, max; 1009 ctf_diff_func_t *funcptr; 1010 ctf_diff_t *cds = arg; 1011 1012 if (cds->cds_ffillip == B_TRUE) { 1013 max = cds->cds_nifuncs; 1014 next = &cds->cds_nextifunc; 1015 funcptr = cds->cds_ifuncs + *next; 1016 } else { 1017 max = cds->cds_nofuncs; 1018 next = &cds->cds_nextofunc; 1019 funcptr = cds->cds_ofuncs + *next; 1020 1021 } 1022 1023 VERIFY(*next < max); 1024 funcptr->cdf_name = name; 1025 funcptr->cdf_symidx = symidx; 1026 funcptr->cdf_matchidx = ULONG_MAX; 1027 *next = *next + 1; 1028 1029 return (0); 1030 } 1031 1032 int 1033 ctf_diff_func_fill(ctf_diff_t *cds) 1034 { 1035 int ret; 1036 uint32_t ifcount, ofcount, idcnt, cti; 1037 ulong_t i, j; 1038 ctf_id_t *iids, *oids; 1039 1040 ifcount = 0; 1041 ofcount = 0; 1042 idcnt = 0; 1043 iids = NULL; 1044 oids = NULL; 1045 1046 ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_count, &ifcount); 1047 if (ret != 0) 1048 return (ret); 1049 ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_count, &ofcount); 1050 if (ret != 0) 1051 return (ret); 1052 1053 cds->cds_ifuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ifcount); 1054 if (cds->cds_ifuncs == NULL) 1055 return (ctf_set_errno(cds->cds_ifp, ENOMEM)); 1056 1057 cds->cds_nifuncs = ifcount; 1058 cds->cds_nextifunc = 0; 1059 1060 cds->cds_ofuncs = ctf_alloc(sizeof (ctf_diff_func_t) * ofcount); 1061 if (cds->cds_ofuncs == NULL) 1062 return (ctf_set_errno(cds->cds_ifp, ENOMEM)); 1063 1064 cds->cds_nofuncs = ofcount; 1065 cds->cds_nextofunc = 0; 1066 1067 cds->cds_ffillip = B_TRUE; 1068 if ((ret = ctf_function_iter(cds->cds_ifp, ctf_diff_func_fill_cb, 1069 cds)) != 0) 1070 return (ret); 1071 1072 cds->cds_ffillip = B_FALSE; 1073 if ((ret = ctf_function_iter(cds->cds_ofp, ctf_diff_func_fill_cb, 1074 cds)) != 0) 1075 return (ret); 1076 1077 /* 1078 * Everything is initialized to not match. This could probably be faster 1079 * with something that used a hash. But this part of the diff isn't used 1080 * by merge. 1081 */ 1082 for (i = 0; i < cds->cds_nifuncs; i++) { 1083 for (j = 0; j < cds->cds_nofuncs; j++) { 1084 ctf_diff_func_t *ifd, *ofd; 1085 ctf_funcinfo_t ifip, ofip; 1086 boolean_t match; 1087 1088 ifd = &cds->cds_ifuncs[i]; 1089 ofd = &cds->cds_ofuncs[j]; 1090 if (strcmp(ifd->cdf_name, ofd->cdf_name) != 0) 1091 continue; 1092 1093 ret = ctf_func_info(cds->cds_ifp, ifd->cdf_symidx, 1094 &ifip); 1095 if (ret != 0) 1096 goto out; 1097 ret = ctf_func_info(cds->cds_ofp, ofd->cdf_symidx, 1098 &ofip); 1099 if (ret != 0) { 1100 ret = ctf_set_errno(cds->cds_ifp, 1101 ctf_errno(cds->cds_ofp)); 1102 goto out; 1103 } 1104 1105 if (ifip.ctc_argc != ofip.ctc_argc && 1106 ifip.ctc_flags != ofip.ctc_flags) 1107 continue; 1108 1109 /* Validate return type and arguments are the same */ 1110 if (ctf_diff_symid(cds, ifip.ctc_return, 1111 ofip.ctc_return)) 1112 continue; 1113 1114 if (ifip.ctc_argc > idcnt) { 1115 if (iids != NULL) 1116 ctf_free(iids, 1117 sizeof (ctf_id_t) * idcnt); 1118 if (oids != NULL) 1119 ctf_free(oids, 1120 sizeof (ctf_id_t) * idcnt); 1121 iids = oids = NULL; 1122 idcnt = ifip.ctc_argc; 1123 iids = ctf_alloc(sizeof (ctf_id_t) * idcnt); 1124 if (iids == NULL) { 1125 ret = ctf_set_errno(cds->cds_ifp, 1126 ENOMEM); 1127 goto out; 1128 } 1129 oids = ctf_alloc(sizeof (ctf_id_t) * idcnt); 1130 if (iids == NULL) { 1131 ret = ctf_set_errno(cds->cds_ifp, 1132 ENOMEM); 1133 goto out; 1134 } 1135 } 1136 1137 if ((ret = ctf_func_args(cds->cds_ifp, ifd->cdf_symidx, 1138 ifip.ctc_argc, iids)) != 0) 1139 goto out; 1140 if ((ret = ctf_func_args(cds->cds_ofp, ofd->cdf_symidx, 1141 ofip.ctc_argc, oids)) != 0) 1142 goto out; 1143 1144 match = B_TRUE; 1145 for (cti = 0; cti < ifip.ctc_argc; cti++) { 1146 if (ctf_diff_symid(cds, iids[cti], oids[cti])) { 1147 match = B_FALSE; 1148 break; 1149 } 1150 } 1151 1152 if (match == B_FALSE) 1153 continue; 1154 1155 ifd->cdf_matchidx = j; 1156 ofd->cdf_matchidx = i; 1157 break; 1158 } 1159 } 1160 1161 ret = 0; 1162 1163 out: 1164 if (iids != NULL) 1165 ctf_free(iids, sizeof (ctf_id_t) * idcnt); 1166 if (oids != NULL) 1167 ctf_free(oids, sizeof (ctf_id_t) * idcnt); 1168 1169 return (ret); 1170 } 1171 1172 /* 1173 * In general, two functions are the same, if they have the same name and their 1174 * arguments have the same types, including the return type. Like types, we 1175 * basically have to do this in two passes. In the first phase we walk every 1176 * type in the first container and try to find a match in the second. 1177 */ 1178 int 1179 ctf_diff_functions(ctf_diff_t *cds, ctf_diff_func_f cb, void *arg) 1180 { 1181 int ret; 1182 ulong_t i; 1183 1184 if (cds->cds_tvalid == B_FALSE) { 1185 if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0) 1186 return (ret); 1187 } 1188 1189 if (cds->cds_fvalid == B_FALSE) { 1190 if ((ret = ctf_diff_func_fill(cds)) != 0) 1191 return (ret); 1192 cds->cds_fvalid = B_TRUE; 1193 } 1194 1195 for (i = 0; i < cds->cds_nifuncs; i++) { 1196 if (cds->cds_ifuncs[i].cdf_matchidx == ULONG_MAX) { 1197 cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx, 1198 B_FALSE, NULL, ULONG_MAX, arg); 1199 } else { 1200 ulong_t idx = cds->cds_ifuncs[i].cdf_matchidx; 1201 cb(cds->cds_ifp, cds->cds_ifuncs[i].cdf_symidx, B_TRUE, 1202 cds->cds_ofp, cds->cds_ofuncs[idx].cdf_symidx, arg); 1203 } 1204 } 1205 1206 for (i = 0; i < cds->cds_nofuncs; i++) { 1207 if (cds->cds_ofuncs[i].cdf_matchidx != ULONG_MAX) 1208 continue; 1209 cb(cds->cds_ofp, cds->cds_ofuncs[i].cdf_symidx, B_FALSE, 1210 NULL, ULONG_MAX, arg); 1211 } 1212 1213 return (0); 1214 } 1215 1216 static int 1217 ctf_diff_obj_fill_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg) 1218 { 1219 uint_t *next, max; 1220 ctf_diff_obj_t *objptr; 1221 ctf_diff_t *cds = arg; 1222 1223 if (cds->cds_ofillip == B_TRUE) { 1224 max = cds->cds_niobj; 1225 next = &cds->cds_nextiobj; 1226 objptr = cds->cds_iobj + *next; 1227 } else { 1228 max = cds->cds_noobj; 1229 next = &cds->cds_nextoobj; 1230 objptr = cds->cds_oobj+ *next; 1231 1232 } 1233 1234 VERIFY(*next < max); 1235 objptr->cdo_name = name; 1236 objptr->cdo_symidx = symidx; 1237 objptr->cdo_id = id; 1238 objptr->cdo_matchidx = ULONG_MAX; 1239 *next = *next + 1; 1240 1241 return (0); 1242 } 1243 1244 /* ARGSUSED */ 1245 static int 1246 ctf_diff_obj_count(const char *name, ctf_id_t id, ulong_t symidx, void *arg) 1247 { 1248 uint32_t *count = arg; 1249 1250 *count = *count + 1; 1251 1252 return (0); 1253 } 1254 1255 1256 static int 1257 ctf_diff_obj_fill(ctf_diff_t *cds) 1258 { 1259 int ret; 1260 uint32_t iocount, oocount; 1261 ulong_t i, j; 1262 1263 iocount = 0; 1264 oocount = 0; 1265 1266 ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_count, &iocount); 1267 if (ret != 0) 1268 return (ret); 1269 1270 ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_count, &oocount); 1271 if (ret != 0) 1272 return (ret); 1273 1274 cds->cds_iobj = ctf_alloc(sizeof (ctf_diff_obj_t) * iocount); 1275 if (cds->cds_iobj == NULL) 1276 return (ctf_set_errno(cds->cds_ifp, ENOMEM)); 1277 cds->cds_niobj = iocount; 1278 cds->cds_nextiobj = 0; 1279 1280 cds->cds_oobj = ctf_alloc(sizeof (ctf_diff_obj_t) * oocount); 1281 if (cds->cds_oobj == NULL) 1282 return (ctf_set_errno(cds->cds_ifp, ENOMEM)); 1283 cds->cds_noobj = oocount; 1284 cds->cds_nextoobj = 0; 1285 1286 cds->cds_ofillip = B_TRUE; 1287 if ((ret = ctf_object_iter(cds->cds_ifp, ctf_diff_obj_fill_cb, 1288 cds)) != 0) 1289 return (ret); 1290 1291 cds->cds_ofillip = B_FALSE; 1292 if ((ret = ctf_object_iter(cds->cds_ofp, ctf_diff_obj_fill_cb, 1293 cds)) != 0) 1294 return (ret); 1295 1296 for (i = 0; i < cds->cds_niobj; i++) { 1297 for (j = 0; j < cds->cds_noobj; j++) { 1298 ctf_diff_obj_t *id, *od; 1299 1300 id = &cds->cds_iobj[i]; 1301 od = &cds->cds_oobj[j]; 1302 1303 if (id->cdo_name == NULL || od->cdo_name == NULL) 1304 continue; 1305 if (strcmp(id->cdo_name, od->cdo_name) != 0) 1306 continue; 1307 1308 if (ctf_diff_symid(cds, id->cdo_id, od->cdo_id)) { 1309 continue; 1310 } 1311 1312 id->cdo_matchidx = j; 1313 od->cdo_matchidx = i; 1314 break; 1315 } 1316 } 1317 1318 return (0); 1319 } 1320 1321 int 1322 ctf_diff_objects(ctf_diff_t *cds, ctf_diff_obj_f cb, void *arg) 1323 { 1324 int ret; 1325 ulong_t i; 1326 1327 if (cds->cds_tvalid == B_FALSE) { 1328 if ((ret = ctf_diff_types(cds, ctf_diff_void_cb, NULL)) != 0) 1329 return (ret); 1330 } 1331 1332 if (cds->cds_ovalid == B_FALSE) { 1333 if ((ret = ctf_diff_obj_fill(cds)) != 0) 1334 return (ret); 1335 cds->cds_ovalid = B_TRUE; 1336 } 1337 1338 for (i = 0; i < cds->cds_niobj; i++) { 1339 ctf_diff_obj_t *o = &cds->cds_iobj[i]; 1340 1341 if (cds->cds_iobj[i].cdo_matchidx == ULONG_MAX) { 1342 cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_FALSE, 1343 NULL, ULONG_MAX, CTF_ERR, arg); 1344 } else { 1345 ctf_diff_obj_t *alt = &cds->cds_oobj[o->cdo_matchidx]; 1346 cb(cds->cds_ifp, o->cdo_symidx, o->cdo_id, B_TRUE, 1347 cds->cds_ofp, alt->cdo_symidx, alt->cdo_id, arg); 1348 } 1349 } 1350 1351 for (i = 0; i < cds->cds_noobj; i++) { 1352 ctf_diff_obj_t *o = &cds->cds_oobj[i]; 1353 if (o->cdo_matchidx != ULONG_MAX) 1354 continue; 1355 cb(cds->cds_ofp, o->cdo_symidx, o->cdo_id, B_FALSE, NULL, 1356 ULONG_MAX, CTF_ERR, arg); 1357 } 1358 1359 return (0); 1360 } 1361