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 * Determine if a shared object definition structure already exists and if 54 * not create one. These definitions provide for recording information 55 * regarding shared objects that are still to be processed. Once processed 56 * shared objects are maintained on the ofl_sos list. The information 57 * recorded in this structure includes: 58 * 59 * o DT_USED requirements. In these cases definitions are added during 60 * mapfile processing of `-' entries (see map_dash()). 61 * 62 * o implicit NEEDED entries. As shared objects are processed from the 63 * command line so any of their dependencies are recorded in these 64 * structures for later processing (see process_dynamic()). 65 * 66 * o version requirements. Any explicit shared objects that have version 67 * dependencies on other objects have their version requirements recorded. 68 * In these cases definitions are added during mapfile processing of `-' 69 * entries (see map_dash()). Also, shared objects may have versioning 70 * requirements on their NEEDED entries. These cases are added during 71 * their version processing (see vers_need_process()). 72 * 73 * Note: Both process_dynamic() and vers_need_process() may generate the 74 * initial version definition structure because you can't rely on what 75 * section (.dynamic or .SUNW_version) may be processed first from any 76 * input file. 77 */ 78 Sdf_desc * 79 sdf_find(const char *name, APlist *alp) 80 { 81 Aliste idx; 82 Sdf_desc *sdf; 83 84 for (APLIST_TRAVERSE(alp, idx, sdf)) 85 if (strcmp(name, sdf->sdf_name) == 0) 86 return (sdf); 87 88 return (NULL); 89 } 90 91 Sdf_desc * 92 sdf_add(const char *name, APlist **alpp) 93 { 94 Sdf_desc *sdf; 95 96 if ((sdf = libld_calloc(1, sizeof (Sdf_desc))) == NULL) 97 return ((Sdf_desc *)S_ERROR); 98 99 sdf->sdf_name = name; 100 101 if (aplist_append(alpp, sdf, AL_CNT_OFL_LIBS) == NULL) 102 return ((Sdf_desc *)S_ERROR); 103 104 return (sdf); 105 } 106 107 /* 108 * Add a string, separated by a colon, to an existing string. Typically used 109 * to maintain filter, rpath and audit names, of which there is normally only 110 * one string supplied anyway. 111 */ 112 char * 113 add_string(char *old, char *str) 114 { 115 char *new; 116 117 if (old) { 118 char *_str; 119 size_t len; 120 121 /* 122 * If an original string exists, make sure this new string 123 * doesn't get duplicated. 124 */ 125 if ((_str = strstr(old, str)) != NULL) { 126 if (((_str == old) || 127 (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) && 128 (_str += strlen(str)) && 129 ((*_str == '\0') || 130 (*_str == *(MSG_ORIG(MSG_STR_COLON))))) 131 return (old); 132 } 133 134 len = strlen(old) + strlen(str) + 2; 135 if ((new = libld_calloc(1, len)) == NULL) 136 return ((char *)S_ERROR); 137 (void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str); 138 } else { 139 if ((new = libld_malloc(strlen(str) + 1)) == NULL) 140 return ((char *)S_ERROR); 141 (void) strcpy(new, str); 142 } 143 144 return (new); 145 } 146 147 /* 148 * The GNU ld '-wrap=XXX' and '--wrap=XXX' options correspond to our 149 * '-z wrap=XXX'. When str2chr() does this conversion, we end up with 150 * the return character set to 'z' and optarg set to 'XXX'. This callback 151 * changes optarg to include the missing wrap= prefix. 152 * 153 * exit: 154 * Returns c on success, or '?' on error. 155 */ 156 static int 157 str2chr_wrap_cb(int c) 158 { 159 char *str; 160 size_t len = MSG_ARG_WRAP_SIZE + strlen(optarg) + 1; 161 162 if ((str = libld_malloc(len)) == NULL) 163 return ('?'); 164 (void) snprintf(str, len, MSG_ORIG(MSG_FMT_STRCAT), 165 MSG_ORIG(MSG_ARG_WRAP), optarg); 166 optarg = str; 167 return (c); 168 } 169 170 /* 171 * Determine whether this string, possibly with an associated option, should 172 * be translated to an option character. If so, update the optind and optarg 173 * and optopt as described for short options in getopt(3c). 174 * 175 * entry: 176 * lml - Link map list for debug messages 177 * ndx - Starting optind for current item 178 * argc, argv - Command line arguments 179 * arg - Option to be examined 180 * c, opt - Option character (c) and corresponding long name (opt) 181 * optsz - 0 if option does not accept a value. If option does 182 * accept a value, strlen(opt), giving the offset to the 183 * value if the option and value are combined in one string. 184 * cbfunc - NULL, or pointer to function to call if a translation is 185 * successful. 186 */ 187 static int 188 str2chr(Lm_list *lml, int ndx, int argc, char **argv, char *arg, int c, 189 const char *opt, size_t optsz, int (*cbfunc)(int)) 190 { 191 if (optsz == 0) { 192 /* 193 * Compare a single option (ie. there's no associated option 194 * argument). 195 */ 196 if (strcmp(arg, opt) == 0) { 197 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 198 optind += 1; 199 optopt = c; 200 return (c); 201 } 202 } else if ((strcmp(arg, opt) == 0) || 203 ((arg[optsz] == '=') && strncmp(arg, opt, optsz) == 0)) { 204 /* 205 * Otherwise, compare the option name, which may be 206 * concatenated with the option argument. 207 */ 208 DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c)); 209 210 if (arg[optsz] == '\0') { 211 /* 212 * Optarg is the next argument (white space separated). 213 * Make sure an optarg is available, and if not return 214 * a failure to prevent any fall-through to the generic 215 * getopt() processing. 216 * 217 * Since we'll be completely failing this option we 218 * don't want to update optopt with the translation, 219 * but also need to set it to _something_. Setting it 220 * to the '-' of the argument causes us to behave 221 * correctly. 222 */ 223 if ((++optind + 1) > argc) { 224 optopt = arg[0]; 225 return ('?'); 226 } 227 optarg = argv[optind]; 228 optind++; 229 } else { 230 /* 231 * GNU option/option argument pairs can be represented 232 * with a "=" separator. If this is the case, remove 233 * the separator. 234 */ 235 optarg = &arg[optsz]; 236 optind++; 237 if (*optarg == '=') { 238 if (*(++optarg) == '\0') { 239 optopt = arg[0]; 240 return ('?'); 241 } 242 } 243 } 244 245 if (cbfunc != NULL) 246 c = (*cbfunc)(c); 247 optopt = c; 248 return (c); 249 } 250 return (0); 251 } 252 253 /* 254 * Parse an individual option. The intent of this function is to determine if 255 * any known, non-Solaris options have been passed to ld(1). This condition 256 * can occur as a result of build configuration tools, because of users 257 * familiarity with other systems, or simply the users preferences. If a known 258 * non-Solaris option can be determined, translate that option into the Solaris 259 * counterpart. 260 * 261 * This function will probably never be a complete solution, as new, non-Solaris 262 * options are discovered, their translation will have to be added. Other 263 * non-Solaris options are incompatible with the Solaris link-editor, and will 264 * never be recognized. We support what we can. 265 */ 266 int 267 ld_getopt(Lm_list *lml, int ndx, int argc, char **argv) 268 { 269 int c; 270 271 if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) { 272 char *arg = &argv[optind][1]; 273 274 switch (*arg) { 275 case 'r': 276 /* Translate -rpath <optarg> to -R <optarg> */ 277 if ((c = str2chr(lml, ndx, argc, argv, arg, 'R', 278 MSG_ORIG(MSG_ARG_T_RPATH), 279 MSG_ARG_T_RPATH_SIZE, NULL)) != 0) { 280 return (c); 281 } 282 break; 283 case 's': 284 /* Translate -shared to -G */ 285 if ((c = str2chr(lml, ndx, argc, argv, arg, 'G', 286 MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) { 287 return (c); 288 289 /* Translate -soname <optarg> to -h <optarg> */ 290 } else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h', 291 MSG_ORIG(MSG_ARG_T_SONAME), 292 MSG_ARG_T_SONAME_SIZE, NULL)) != 0) { 293 return (c); 294 } 295 break; 296 case 'w': 297 /* Translate -wrap to -z wrap= */ 298 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 299 MSG_ORIG(MSG_ARG_T_WRAP) + 1, 300 MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) { 301 return (c); 302 } 303 break; 304 case '(': 305 /* 306 * Translate -( to -z rescan-start 307 */ 308 if ((c = str2chr(lml, ndx, argc, argv, 309 arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) != 310 0) { 311 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START); 312 return (c); 313 } 314 break; 315 case ')': 316 /* 317 * Translate -) to -z rescan-end 318 */ 319 if ((c = str2chr(lml, ndx, argc, argv, 320 arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) != 321 0) { 322 optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END); 323 return (c); 324 } 325 break; 326 case '-': 327 switch (*(arg + 1)) { 328 case 'a': 329 /* 330 * Translate --allow-multiple-definition to 331 * -zmuldefs 332 */ 333 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 334 MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) != 335 0) { 336 optarg = 337 (char *)MSG_ORIG(MSG_ARG_MULDEFS); 338 return (c); 339 340 /* 341 * Translate --auxiliary <optarg> to 342 * -f <optarg> 343 */ 344 } else if ((c = str2chr(lml, argc, ndx, argv, 345 arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR), 346 MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) { 347 return (c); 348 } 349 break; 350 case 'd': 351 /* 352 * Translate --dynamic-linker <optarg> to 353 * -I <optarg> 354 */ 355 if ((c = str2chr(lml, ndx, argc, argv, arg, 'I', 356 MSG_ORIG(MSG_ARG_T_INTERP), 357 MSG_ARG_T_INTERP_SIZE, NULL)) != 0) { 358 return (c); 359 } 360 break; 361 case 'e': 362 /* Translate --entry <optarg> to -e <optarg> */ 363 if ((c = str2chr(lml, ndx, argc, argv, arg, 'e', 364 MSG_ORIG(MSG_ARG_T_ENTRY), 365 MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) { 366 return (c); 367 } 368 /* 369 * Translate --end-group to -z rescan-end 370 */ 371 if ((c = str2chr(lml, ndx, argc, argv, 372 arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP), 373 0, NULL)) != 0) { 374 optarg = (char *) 375 MSG_ORIG(MSG_ARG_RESCAN_END); 376 return (c); 377 } 378 break; 379 case 'f': 380 /* 381 * Translate --fatal-warnings to 382 * -z fatal-warnings. 383 */ 384 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 385 MSG_ORIG(MSG_ARG_T_FATWARN), 386 0, NULL)) != 0) { 387 optarg = (char *) 388 MSG_ORIG(MSG_ARG_FATWARN); 389 return (c); 390 } 391 /* Translate --filter <optarg> to -F <optarg> */ 392 if ((c = str2chr(lml, ndx, argc, argv, arg, 'F', 393 MSG_ORIG(MSG_ARG_T_STDFLTR), 394 MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) { 395 return (c); 396 } 397 break; 398 case 'h': 399 /* Translate --help to -zhelp */ 400 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 401 MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) != 402 0) { 403 optarg = (char *)MSG_ORIG(MSG_ARG_HELP); 404 return (c); 405 } 406 break; 407 case 'l': 408 /* 409 * Translate --library <optarg> to -l <optarg> 410 */ 411 if ((c = str2chr(lml, ndx, argc, argv, arg, 'l', 412 MSG_ORIG(MSG_ARG_T_LIBRARY), 413 MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) { 414 return (c); 415 416 /* 417 * Translate --library-path <optarg> to 418 * -L <optarg> 419 */ 420 } else if ((c = str2chr(lml, ndx, argc, argv, 421 arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH), 422 MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) { 423 return (c); 424 } 425 break; 426 case 'n': 427 /* 428 * Translate --no-fatal-warnings to 429 * -z nofatal-warnings. 430 */ 431 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 432 MSG_ORIG(MSG_ARG_T_NOFATWARN), 433 0, NULL)) != 0) { 434 optarg = (char *) 435 MSG_ORIG(MSG_ARG_NOFATWARN); 436 return (c); 437 } 438 439 /* Translate --no-undefined to -zdefs */ 440 if ((c = str2chr(lml, ndx, argc, argv, arg, 'z', 441 MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) != 442 0) { 443 optarg = (char *)MSG_ORIG(MSG_ARG_DEFS); 444 return (c); 445 446 /* 447 * Translate --no-whole-archive to 448 * -z defaultextract 449 */ 450 } else if ((c = str2chr(lml, ndx, argc, argv, 451 arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC), 452 0, NULL)) != 0) { 453 optarg = 454 (char *)MSG_ORIG(MSG_ARG_DFLEXTRT); 455 return (c); 456 } 457 break; 458 case 'o': 459 /* Translate --output <optarg> to -o <optarg> */ 460 if ((c = str2chr(lml, ndx, argc, argv, arg, 'o', 461 MSG_ORIG(MSG_ARG_T_OUTPUT), 462 MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) { 463 return (c); 464 } 465 break; 466 case 'r': 467 /* Translate --relocatable to -r */ 468 if ((c = str2chr(lml, ndx, argc, argv, arg, 'r', 469 MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0, 470 NULL)) != 0) { 471 return (c); 472 } 473 break; 474 case 's': 475 /* Translate --strip-all to -s */ 476 if ((c = str2chr(lml, ndx, argc, argv, arg, 's', 477 MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) != 478 0) { 479 return (c); 480 } 481 /* 482 * Translate --start-group to -z rescan-start 483 */ 484 if ((c = str2chr(lml, ndx, argc, argv, 485 arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP), 486 0, NULL)) != 0) { 487 optarg = (char *) 488 MSG_ORIG(MSG_ARG_RESCAN_START); 489 return (c); 490 } 491 break; 492 case 'u': 493 /* 494 * Translate --undefined <optarg> to 495 * -u <optarg> 496 */ 497 if ((c = str2chr(lml, ndx, argc, argv, arg, 'u', 498 MSG_ORIG(MSG_ARG_T_UNDEF), 499 MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) { 500 return (c); 501 } 502 break; 503 case 'v': 504 /* Translate --version to -V */ 505 if ((c = str2chr(lml, ndx, argc, argv, arg, 'V', 506 MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) != 507 0) { 508 return (c); 509 } 510 break; 511 case 'w': 512 /* 513 * Translate --whole-archive to -z alltextract 514 */ 515 if ((c = str2chr(lml, ndx, argc, argv, 516 arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC), 517 0, NULL)) != 0) { 518 optarg = 519 (char *)MSG_ORIG(MSG_ARG_ALLEXTRT); 520 return (c); 521 } 522 /* 523 * Translate --wrap to -z wrap= 524 */ 525 if ((c = str2chr(lml, ndx, argc, argv, 526 arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP), 527 MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) != 528 0) { 529 return (c); 530 } 531 break; 532 } 533 break; 534 } 535 } 536 537 if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) { 538 /* 539 * It is possible that a "-Wl," argument has been used to 540 * specify an option. This isn't advertized ld(1) syntax, but 541 * compiler drivers and configuration tools, have been known to 542 * pass this compiler option to ld(1). Strip off the "-Wl," 543 * prefix and pass the option through. 544 */ 545 if ((c == 'W') && (strncmp(optarg, 546 MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) { 547 DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg)); 548 c = optarg[MSG_ARG_T_WL_SIZE]; 549 optarg += MSG_ARG_T_WL_SIZE + 1; 550 } 551 } 552 553 return (c); 554 } 555 556 /* 557 * A compare routine for Isd_node AVL trees. 558 */ 559 int 560 isdavl_compare(const void *n1, const void *n2) 561 { 562 uint_t hash1, hash2; 563 const char *st1, *st2; 564 int rc; 565 566 hash1 = ((Isd_node *)n1)->isd_hash; 567 hash2 = ((Isd_node *)n2)->isd_hash; 568 569 if (hash1 > hash2) 570 return (1); 571 if (hash1 < hash2) 572 return (-1); 573 574 st1 = ((Isd_node *)n1)->isd_name; 575 st2 = ((Isd_node *)n2)->isd_name; 576 577 rc = strcmp(st1, st2); 578 if (rc > 0) 579 return (1); 580 if (rc < 0) 581 return (-1); 582 return (0); 583 } 584 585 /* 586 * Messaging support - funnel everything through dgettext(). 587 */ 588 const char * 589 _libld_msg(Msg mid) 590 { 591 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 592 } 593 594 /* 595 * Determine whether a symbol name should be demangled. 596 */ 597 const char * 598 demangle(const char *name) 599 { 600 if (demangle_flag) 601 return (Elf_demangle_name(name)); 602 else 603 return (name); 604 } 605 606 /* 607 * Compare a series of platform or machine hardware names. 608 */ 609 int 610 cap_names_match(Alist *alp1, Alist *alp2) 611 { 612 Capstr *capstr1; 613 Aliste idx1; 614 int match = 0; 615 Word nitems; 616 617 if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2)) 618 return (1); 619 620 for (ALIST_TRAVERSE(alp1, idx1, capstr1)) { 621 Capstr *capstr2; 622 Aliste idx2; 623 624 for (ALIST_TRAVERSE(alp2, idx2, capstr2)) { 625 if (strcmp(capstr1->cs_str, capstr2->cs_str)) 626 continue; 627 628 match++; 629 break; 630 } 631 } 632 633 if (nitems == match) 634 return (0); 635 636 return (1); 637 } 638