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