1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright (c) 1988 AT&T 28 * All Rights Reserved 29 */ 30 31 /* 32 * Utility functions 33 */ 34 #include <unistd.h> 35 #include <stdio.h> 36 #include <stdarg.h> 37 #include <string.h> 38 #include <fcntl.h> 39 #include <sys/types.h> 40 #include <sys/mman.h> 41 #include <errno.h> 42 #include <sgs.h> 43 #include <libintl.h> 44 #include <debug.h> 45 #include "msg.h" 46 #include "_libld.h" 47 48 /* 49 * libld_malloc() and dz_map() are used for both performance and for ease of 50 * programming: 51 * 52 * Performance: 53 * The link-edit is a short lived process which doesn't really free much 54 * of the dynamic memory that it requests. Because of this, it is more 55 * important to optimize for quick memory allocations than the 56 * re-usability of the memory. 57 * 58 * By also mmaping blocks of pages in from /dev/zero we don't need to 59 * waste the overhead of zeroing out these pages for calloc() requests. 60 * 61 * Memory Management: 62 * By doing all libld memory management through the ld_malloc routine 63 * it's much easier to free up all memory at the end by simply unmaping 64 * all of the blocks that were mapped in through dz_map(). This is much 65 * simpler then trying to track all of the libld structures that were 66 * dynamically allocate and are actually pointers into the ELF files. 67 * 68 * It's important that we can free up all of our dynamic memory because 69 * libld is used by ld.so.1 when it performs dlopen()'s of relocatable 70 * objects. 71 * 72 * Format: 73 * The memory blocks for each allocation store the size of the allocation 74 * in the first 8 bytes of the block. The pointer that is returned by 75 * libld_malloc() is actually the address of (block + 8): 76 * 77 * (addr - 8) block_size 78 * (addr) <allocated block> 79 * 80 * The size is retained in order to implement realloc(), and to perform 81 * the required memcpy(). 8 bytes are uses, as the memory area returned 82 * by libld_malloc() must be 8 byte-aligned. Even in a 32-bit environment, 83 * u_longlog_t pointers are employed. 84 * 85 * Map anonymous memory via MAP_ANON (added in Solaris 8). 86 */ 87 static void * 88 dz_map(size_t size) 89 { 90 void *addr; 91 92 if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC), 93 (MAP_PRIVATE | MAP_ANON), -1, 0)) == MAP_FAILED) { 94 int err = errno; 95 eprintf(NULL, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON), 96 strerror(err)); 97 return (MAP_FAILED); 98 } 99 return (addr); 100 } 101 102 void * 103 libld_malloc(size_t size) 104 { 105 Ld_heap *chp = ld_heap; 106 void *vptr; 107 size_t asize = size + HEAPALIGN; 108 109 /* 110 * If this is the first allocation, or the allocation request is greater 111 * than the current free space available, allocate a new heap. 112 */ 113 if ((chp == NULL) || 114 (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) { 115 Ld_heap *nhp; 116 size_t hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN); 117 size_t tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN); 118 119 /* 120 * Allocate a block that is at minimum 'HEAPBLOCK' size 121 */ 122 if (tsize < HEAPBLOCK) 123 tsize = HEAPBLOCK; 124 125 if ((nhp = dz_map(tsize)) == MAP_FAILED) 126 return (NULL); 127 128 nhp->lh_next = chp; 129 nhp->lh_free = (void *)((size_t)nhp + hsize); 130 nhp->lh_end = (void *)((size_t)nhp + tsize); 131 132 ld_heap = chp = nhp; 133 } 134 vptr = chp->lh_free; 135 136 /* 137 * Assign size to head of allocated block (used by realloc), and 138 * memory arena as then next 8-byte aligned offset. 139 */ 140 *((size_t *)vptr) = size; 141 vptr = (void *)((size_t)vptr + HEAPALIGN); 142 143 /* 144 * Increment free to point to next available block 145 */ 146 chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize, 147 HEAPALIGN); 148 149 return (vptr); 150 } 151 152 void * 153 libld_realloc(void *ptr, size_t size) 154 { 155 size_t psize; 156 void *vptr; 157 158 if (ptr == NULL) 159 return (libld_malloc(size)); 160 161 /* 162 * Size of the allocated blocks is stored *just* before the blocks 163 * address. 164 */ 165 psize = *((size_t *)((size_t)ptr - HEAPALIGN)); 166 167 /* 168 * If the block actually fits then just return. 169 */ 170 if (size <= psize) 171 return (ptr); 172 173 if ((vptr = libld_malloc(size)) != NULL) 174 (void) memcpy(vptr, ptr, psize); 175 176 return (vptr); 177 } 178 179 void 180 /* ARGSUSED 0 */ 181 libld_free(void *ptr) 182 { 183 } 184 185 /* 186 * Determine if a shared object definition structure already exists and if 187 * not create one. These definitions provide for recording information 188 * regarding shared objects that are still to be processed. Once processed 189 * shared objects are maintained on the ofl_sos list. The information 190 * recorded in this structure includes: 191 * 192 * o DT_USED requirements. In these cases definitions are added during 193 * mapfile processing of `-' entries (see map_dash()). 194 * 195 * o implicit NEEDED entries. As shared objects are processed from the 196 * command line so any of their dependencies are recorded in these 197 * structures for later processing (see process_dynamic()). 198 * 199 * o version requirements. Any explicit shared objects that have version 200 * dependencies on other objects have their version requirements recorded. 201 * In these cases definitions are added during mapfile processing of `-' 202 * entries (see map_dash()). Also, shared objects may have versioning 203 * requirements on their NEEDED entries. These cases are added during 204 * their version processing (see vers_need_process()). 205 * 206 * Note: Both process_dynamic() and vers_need_process() may generate the 207 * initial version definition structure because you can't rely on what 208 * section (.dynamic or .SUNW_version) may be processed first from any 209 * input file. 210 */ 211 Sdf_desc * 212 sdf_find(const char *name, APlist *alp) 213 { 214 Aliste idx; 215 Sdf_desc *sdf; 216 217 for (APLIST_TRAVERSE(alp, idx, sdf)) 218 if (strcmp(name, sdf->sdf_name) == 0) 219 return (sdf); 220 221 return (NULL); 222 } 223 224 Sdf_desc * 225 sdf_add(const char *name, APlist **alpp) 226 { 227 Sdf_desc *sdf; 228 229 if ((sdf = libld_calloc(sizeof (Sdf_desc), 1)) == NULL) 230 return ((Sdf_desc *)S_ERROR); 231 232 sdf->sdf_name = name; 233 234 if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL) 235 return ((Sdf_desc *)S_ERROR); 236 237 return (sdf); 238 } 239 240 /* 241 * Add a string, separated by a colon, to an existing string. Typically used 242 * to maintain filter, rpath and audit names, of which there is normally only 243 * one string supplied anyway. 244 */ 245 char * 246 add_string(char *old, char *str) 247 { 248 char *new; 249 250 if (old) { 251 char *_str; 252 size_t len; 253 254 /* 255 * If an original string exists, make sure this new string 256 * doesn't get duplicated. 257 */ 258 if ((_str = strstr(old, str)) != NULL) { 259 if (((_str == old) || 260 (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) && 261 (_str += strlen(str)) && 262 ((*_str == '\0') || 263 (*_str == *(MSG_ORIG(MSG_STR_COLON))))) 264 return (old); 265 } 266 267 len = strlen(old) + strlen(str) + 2; 268 if ((new = libld_calloc(1, len)) == NULL) 269 return ((char *)S_ERROR); 270 (void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str); 271 } else { 272 if ((new = libld_malloc(strlen(str) + 1)) == NULL) 273 return ((char *)S_ERROR); 274 (void) strcpy(new, str); 275 } 276 277 return (new); 278 } 279 280 /* 281 * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our 282 * '-z wrap=XXX'. When str2chr() does this conversion, we end up with 283 * the return character set to 'z' and optarg set to 'XXX'. This callback 284 * changes optarg to include the missing wrap= prefix. 285 * 286 * exit: 287 * Returns c on success, or '?' on error. 288 */ 289 static int 290 str2chr_wrap_cb(int c) 291 { 292 char *str; 293 size_t len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1; 294 295 if ((str = libld_malloc(len)) == NULL) 296 return ('?'); 297 (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT), 298 MSG_ORIG(MSG_ARG_WRAP), optarg); 299 optarg = str; 300 return (c); 301 } 302 303 /* 304 * Determine whether this string, possibly with an associated option, should 305 * be translated to an option character. If so, update the optind and optarg 306 * and optopt as described for short options in getopt(3c). 307 * 308 * entry: 309 * lml - Link map list for debug messages 310 * ndx - Starting optind for current item 311 * argc, argv - Command line arguments 312 * arg - Option to be examined 313 * c, opt - Option character (c) and corresponding long name (opt) 314 * optsz - 0 if option does not accept a value. If option does 315 * accept a value, strlen(opt), giving the offset to the 316 * value if the option and value are combined in one string. 317 * cbfunc - NULL, or pointer to function to call if a translation is 318 * successful. 319 */ 320 static int 321 str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c, 322 const char *opt, size_t optsz, int cbfunc(int)) 323 { 324 if (optsz == 0) { 325 /* 326 * Compare a single option (ie. there's no associated option 327 * argument). 328 */ 329 if (strcmp(arg, opt) == 0) { 330 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 331 optind += 1; 332 optopt = c; 333 return (c); 334 } 335 } else if ((strcmp(arg, opt) == 0) || 336 ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) { 337 /* 338 * Otherwise, compare the option name, which may be 339 * concatenated with the option argument. 340 */ 341 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 342 343 if (arg[optsz] == '\0') { 344 /* 345 * Optarg is the next argument (white space separated). 346 * Make sure an optarg is available, and if not return 347 * a failure to prevent any fall-through to the generic 348 * getopt() processing. 349 * 350 * Since we'll be completely failing this option we 351 * don't want to update optopt with the translation, 352 * but also need to set it to _something_. Setting it 353 * to the '-' of the argument causes us to behave 354 * correctly. 355 */ 356 if ((++optind + 1) > argc) { 357 optopt = arg[0]; 358 return ('?'); 359 } 360 optarg = argv[optind]; 361 optind++; 362 } else { 363 /* 364 * GNU option/option argument pairs can be represented 365 * with a "=" separator. If this is the case, remove 366 * the separator. 367 */ 368 optarg = &arg[optsz]; 369 optind++; 370 if (*optarg == '=') { 371 if (*(++optarg) == '\0') { 372 optopt = arg[0]; 373 return ('?'); 374 } 375 } 376 } 377 378 if (cbfunc != NULL) 379 c = (*cbfunc)(c); 380 optopt = c; 381 return (c); 382 } 383 return (0); 384 } 385 386 /* 387 * Parse an individual option. The intent of this function is to determine if 388 * any known, non-Solaris options have been passed to ld(1). This condition 389 * can occur as a result of build configuration tools, because of users 390 * familiarity with other systems, or simply the users preferences. If a known 391 * non-Solaris option can be determined, translate that option into the Solaris 392 * counterpart. 393 * 394 * This function will probably never be a complete solution, as new, non-Solaris 395 * options are discovered, their translation will have to be added. Other 396 * non-Solaris options are incompatible with the Solaris link-editor, and will 397 * never be recognized. We support what we can. 398 */ 399 int 400 ld_getopt(Lm_list *lml, int ndx, int argc, char **argv) 401 { 402 int c; 403 404 if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) { 405 char *arg = &argv[optind][1]; 406 407 switch (*arg) { 408 case 'r': 409 /* Translate -rpath <optarg> to -R <optarg> */ 410 if ((c = str2chr(lml, ndx, argc, argv, arg, 'R', 411 MSG_ORIG(MSG_ARG_T_RPATH), 412 MSG_ARG_T_RPATH_SIZE, NULL)) != 0) { 413 return (c); 414 } 415 break; 416 case 's': 417 /* Translate -shared to -G */ 418 if ((c = str2chr(lml, ndx, argc, argv, arg, 'G', 419 MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) { 420 return (c); 421 422 /* Translate -soname <optarg> to -h <optarg> */ 423 } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h', 424 MSG_ORIG(MSG_ARG_T_SONAME), 425 MSG_ARG_T_SONAME_SIZE, NULL)) != 0) { 426 return (c); 427 } 428 break; 429 case 'w': 430 /* Translate -wrap to -z wrap= */ 431 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 432 MSG_ORIG(MSG_ARG_T_WRAP) + 1, 433 MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) { 434 return (c); 435 } 436 break; 437 case '(': 438 /* 439 * Translate -( to -z rescan-start 440 */ 441 if ((c = str2chr(lml, ndx, argc, argv, 442 arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) != 443 0) { 444 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START); 445 return (c); 446 } 447 break; 448 case ')': 449 /* 450 * Translate -) to -z rescan-end 451 */ 452 if ((c = str2chr(lml, ndx, argc, argv, 453 arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) != 454 0) { 455 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END); 456 return (c); 457 } 458 break; 459 case '-': 460 switch (*(arg + 1)) { 461 case 'a': 462 /* 463 * Translate --as-needed to -zignore 464 */ 465 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 466 MSG_ORIG(MSG_ARG_T_ASNEEDED), 0, NULL)) != 467 0) { 468 optarg = 469 (char *)MSG_ORIG(MSG_ARG_IGNORE); 470 return (c); 471 } 472 /* 473 * Translate --allow-multiple-definition to 474 * -zmuldefs 475 */ 476 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 477 MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) != 478 0) { 479 optarg = 480 (char *)MSG_ORIG(MSG_ARG_MULDEFS); 481 return (c); 482 } 483 /* 484 * Translate --auxiliary <optarg> to 485 * -f <optarg> 486 */ 487 if ((c = str2chr(lml, argc, ndx, argv, 488 arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR), 489 MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) { 490 return (c); 491 } 492 break; 493 case 'd': 494 /* 495 * Translate --dynamic-linker <optarg> to 496 * -I <optarg> 497 */ 498 if ((c = str2chr(lml, ndx, argc, argv, arg, 'I', 499 MSG_ORIG(MSG_ARG_T_INTERP), 500 MSG_ARG_T_INTERP_SIZE, NULL)) != 0) { 501 return (c); 502 } 503 break; 504 case 'e': 505 /* Translate --entry <optarg> to -e <optarg> */ 506 if ((c = str2chr(lml, ndx, argc, argv, arg, 'e', 507 MSG_ORIG(MSG_ARG_T_ENTRY), 508 MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) { 509 return (c); 510 } 511 /* 512 * Translate --end-group to -z rescan-end 513 */ 514 if ((c = str2chr(lml, ndx, argc, argv, 515 arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP), 516 0, NULL)) != 0) { 517 optarg = (char *) 518 MSG_ORIG(MSG_ARG_RESCAN_END); 519 return (c); 520 } 521 break; 522 case 'f': 523 /* 524 * Translate --fatal-warnings to 525 * -z fatal-warnings. 526 */ 527 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 528 MSG_ORIG(MSG_ARG_T_FATWARN), 529 0, NULL)) != 0) { 530 optarg = (char *) 531 MSG_ORIG(MSG_ARG_FATWARN); 532 return (c); 533 } 534 /* Translate --filter <optarg> to -F <optarg> */ 535 if ((c = str2chr(lml, ndx, argc, argv, arg, 'F', 536 MSG_ORIG(MSG_ARG_T_STDFLTR), 537 MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) { 538 return (c); 539 } 540 break; 541 case 'h': 542 /* Translate --help to -zhelp */ 543 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 544 MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) != 545 0) { 546 optarg = (char *)MSG_ORIG(MSG_ARG_HELP); 547 return (c); 548 } 549 break; 550 case 'l': 551 /* 552 * Translate --library <optarg> to -l <optarg> 553 */ 554 if ((c = str2chr(lml, ndx, argc, argv, arg, 'l', 555 MSG_ORIG(MSG_ARG_T_LIBRARY), 556 MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) { 557 return (c); 558 559 /* 560 * Translate --library-path <optarg> to 561 * -L <optarg> 562 */ 563 } else if ((c = str2chr(lml, ndx, argc, argv, 564 arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH), 565 MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) { 566 return (c); 567 } 568 break; 569 case 'n': 570 /* 571 * Translate --no-as-needed to -zrecord 572 */ 573 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 574 MSG_ORIG(MSG_ARG_T_NOASNEEDED), 0, NULL)) != 575 0) { 576 optarg = 577 (char *)MSG_ORIG(MSG_ARG_RECORD); 578 return (c); 579 } 580 /* 581 * Translate --no-fatal-warnings to 582 * -z nofatal-warnings. 583 */ 584 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 585 MSG_ORIG(MSG_ARG_T_NOFATWARN), 586 0, NULL)) != 0) { 587 optarg = (char *) 588 MSG_ORIG(MSG_ARG_NOFATWARN); 589 return (c); 590 } 591 592 /* Translate --no-undefined to -zdefs */ 593 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 594 MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) != 595 0) { 596 optarg = (char *)MSG_ORIG(MSG_ARG_DEFS); 597 return (c); 598 599 /* 600 * Translate --no-whole-archive to 601 * -z defaultextract 602 */ 603 } else if ((c = str2chr(lml, ndx, argc, argv, 604 arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC), 605 0, NULL)) != 0) { 606 optarg = 607 (char *)MSG_ORIG(MSG_ARG_DFLEXTRT); 608 return (c); 609 } 610 break; 611 case 'o': 612 /* Translate --output <optarg> to -o <optarg> */ 613 if ((c = str2chr(lml, ndx, argc, argv, arg, 'o', 614 MSG_ORIG(MSG_ARG_T_OUTPUT), 615 MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) { 616 return (c); 617 } 618 break; 619 case 'r': 620 /* Translate --relocatable to -r */ 621 if ((c = str2chr(lml, ndx, argc, argv, arg, 'r', 622 MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0, 623 NULL)) != 0) { 624 return (c); 625 } 626 break; 627 case 's': 628 /* Translate --strip-all to -s */ 629 if ((c = str2chr(lml, ndx, argc, argv, arg, 's', 630 MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) != 631 0) { 632 return (c); 633 } 634 /* 635 * Translate --start-group to -z rescan-start 636 */ 637 if ((c = str2chr(lml, ndx, argc, argv, 638 arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP), 639 0, NULL)) != 0) { 640 optarg = (char *) 641 MSG_ORIG(MSG_ARG_RESCAN_START); 642 return (c); 643 } 644 break; 645 case 'u': 646 /* 647 * Translate --undefined <optarg> to 648 * -u <optarg> 649 */ 650 if ((c = str2chr(lml, ndx, argc, argv, arg, 'u', 651 MSG_ORIG(MSG_ARG_T_UNDEF), 652 MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) { 653 return (c); 654 } 655 break; 656 case 'v': 657 /* Translate --version to -V */ 658 if ((c = str2chr(lml, ndx, argc, argv, arg, 'V', 659 MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) != 660 0) { 661 return (c); 662 } 663 break; 664 case 'w': 665 /* 666 * Translate --whole-archive to -z alltextract 667 */ 668 if ((c = str2chr(lml, ndx, argc, argv, 669 arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC), 670 0, NULL)) != 0) { 671 optarg = 672 (char *)MSG_ORIG(MSG_ARG_ALLEXTRT); 673 return (c); 674 } 675 /* 676 * Translate --wrap to -z wrap= 677 */ 678 if ((c = str2chr(lml, ndx, argc, argv, 679 arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP), 680 MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) != 681 0) { 682 return (c); 683 } 684 break; 685 } 686 break; 687 } 688 } 689 690 if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 691 /* 692 * It is possible that a "-Wl," argument has been used to 693 * specify an option. This isn't advertized ld(1) syntax, but 694 * compiler drivers and configuration tools, have been known to 695 * pass this compiler option to ld(1). Strip off the "-Wl," 696 * prefix and pass the option through. 697 */ 698 if ((c == 'W') && (strncmp(optarg, 699 MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) { 700 DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg)); 701 c = optarg[MSG_ARG_T_WL_SIZE]; 702 optarg += MSG_ARG_T_WL_SIZE + 1; 703 } 704 } 705 706 return (c); 707 } 708 709 /* 710 * A compare routine for Isd_node AVL trees. 711 */ 712 int 713 isdavl_compare(const void *n1, const void *n2) 714 { 715 uint_t hash1, hash2; 716 const char *st1, *st2; 717 int rc; 718 719 hash1 = ((Isd_node *)n1)->isd_hash; 720 hash2 = ((Isd_node *)n2)->isd_hash; 721 722 if (hash1 > hash2) 723 return (1); 724 if (hash1 < hash2) 725 return (-1); 726 727 st1 = ((Isd_node *)n1)->isd_name; 728 st2 = ((Isd_node *)n2)->isd_name; 729 730 rc = strcmp(st1, st2); 731 if (rc > 0) 732 return (1); 733 if (rc < 0) 734 return (-1); 735 return (0); 736 } 737 738 /* 739 * Messaging support - funnel everything through dgettext(). 740 */ 741 const char * 742 _libld_msg(Msg mid) 743 { 744 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 745 } 746 747 /* 748 * Determine whether a symbol name should be demangled. 749 */ 750 const char * 751 demangle(const char *name) 752 { 753 if (demangle_flag) 754 return (Elf_demangle_name(name)); 755 else 756 return (name); 757 } 758 759 /* 760 * Compare a series of platform or machine hardware names. 761 */ 762 int 763 cap_names_match(Alist *alp1, Alist *alp2) 764 { 765 Capstr *capstr1; 766 Aliste idx1; 767 int match = 0; 768 Word nitems; 769 770 if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2)) 771 return (1); 772 773 for (ALIST_TRAVERSE(alp1, idx1, capstr1)) { 774 Capstr *capstr2; 775 Aliste idx2; 776 777 for (ALIST_TRAVERSE(alp2, idx2, capstr2)) { 778 if (strcmp(capstr1->cs_str, capstr2->cs_str)) 779 continue; 780 781 match++; 782 break; 783 } 784 } 785 786 if (nitems == match) 787 return (0); 788 789 return (1); 790 }