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 }