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 }