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 */
87static void *
88dz_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
102void *
103libld_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
152void *
153libld_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
179void
180/* ARGSUSED 0 */
181libld_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 */
211Sdf_desc *
212sdf_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
224Sdf_desc *
225sdf_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 */
245char *
246add_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 */
289static int
290str2chr_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 be
305 * translated to an option character.  If so, update the optind and optarg
306 * 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 */
320static int
321str2chr(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			return (c);
333		}
334
335	} else if (strncmp(arg, opt, optsz) == 0) {
336		/*
337		 * Otherwise, compare the option name, which may be
338		 * concatenated with the option argument.
339		 */
340		DBG_CALL(Dbg_args_str2chr(lml, ndx, opt, c));
341
342		if (arg[optsz] == '\0') {
343			/*
344			 * Optarg is the next argument (white space separated).
345			 * Make sure an optarg is available, and if not return
346			 * a failure to prevent any fall-through to the generic
347			 * getopt() processing.
348			 */
349			if ((++optind + 1) > argc) {
350				return ('?');
351			}
352			optarg = argv[optind];
353			optind++;
354		} else {
355			/*
356			 * Optarg concatenated to option (no white space).
357			 * GNU option/option argument pairs can be represented
358			 * with a "=" separator.  If this is the case, remove
359			 * the separator.
360			 */
361			optarg = &arg[optsz];
362			optind++;
363			if (*optarg == '=') {
364				if (*(++optarg) == '\0')
365					return ('?');
366			}
367		}
368
369		if (cbfunc != NULL)
370			c = (*cbfunc)(c);
371
372		return (c);
373	}
374	return (0);
375}
376
377/*
378 * Parse an individual option.  The intent of this function is to determine if
379 * any known, non-Solaris options have been passed to ld(1).  This condition
380 * can occur as a result of build configuration tools, because of users
381 * familiarity with other systems, or simply the users preferences.  If a known
382 * non-Solaris option can be determined, translate that option into the Solaris
383 * counterpart.
384 *
385 * This function will probably never be a complete solution, as new, non-Solaris
386 * options are discovered, their translation will have to be added.  Other
387 * non-Solaris options are incompatible with the Solaris link-editor, and will
388 * never be recognized.  We support what we can.
389 */
390int
391ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
392{
393	int	c;
394
395	if ((optind < argc) && argv[optind] && (argv[optind][0] == '-')) {
396		char	*arg = &argv[optind][1];
397
398		switch (*arg) {
399		case 'r':
400			/* Translate -rpath <optarg> to -R <optarg> */
401			if ((c = str2chr(lml, ndx, argc, argv, arg, 'R',
402			    MSG_ORIG(MSG_ARG_T_RPATH),
403			    MSG_ARG_T_RPATH_SIZE, NULL)) != 0) {
404				return (c);
405			}
406			break;
407		case 's':
408			/* Translate -shared to -G */
409			if ((c = str2chr(lml, ndx, argc, argv, arg, 'G',
410			    MSG_ORIG(MSG_ARG_T_SHARED), 0, NULL)) != 0) {
411				return (c);
412
413			/* Translate -soname <optarg> to -h <optarg> */
414			} else if ((c = str2chr(lml, ndx, argc, argv, arg, 'h',
415			    MSG_ORIG(MSG_ARG_T_SONAME),
416			    MSG_ARG_T_SONAME_SIZE, NULL)) != 0) {
417				return (c);
418			}
419			break;
420		case 'w':
421			/* Translate -wrap to -z wrap= */
422			if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
423			    MSG_ORIG(MSG_ARG_T_WRAP) + 1,
424			    MSG_ARG_T_WRAP_SIZE - 1, str2chr_wrap_cb)) != 0) {
425				return (c);
426			}
427			break;
428		case '(':
429			/*
430			 * Translate -( to -z rescan-start
431			 */
432			if ((c = str2chr(lml, ndx, argc, argv,
433			    arg, 'z', MSG_ORIG(MSG_ARG_T_OPAR), 0, NULL)) !=
434			    0) {
435				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_START);
436				return (c);
437			}
438			break;
439		case ')':
440			/*
441			 * Translate -) to -z rescan-end
442			 */
443			if ((c = str2chr(lml, ndx, argc, argv,
444			    arg, 'z', MSG_ORIG(MSG_ARG_T_CPAR), 0, NULL)) !=
445			    0) {
446				optarg = (char *)MSG_ORIG(MSG_ARG_RESCAN_END);
447				return (c);
448			}
449			break;
450		case '-':
451			switch (*(arg + 1)) {
452			case 'a':
453				/*
454				 * Translate --allow-multiple-definition to
455				 * -zmuldefs
456				 */
457				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
458				    MSG_ORIG(MSG_ARG_T_MULDEFS), 0, NULL)) !=
459				    0) {
460					optarg =
461					    (char *)MSG_ORIG(MSG_ARG_MULDEFS);
462					return (c);
463
464				/*
465				 * Translate --auxiliary <optarg> to
466				 * -f <optarg>
467				 */
468				} else if ((c = str2chr(lml, argc, ndx, argv,
469				    arg, 'f', MSG_ORIG(MSG_ARG_T_AUXFLTR),
470				    MSG_ARG_T_AUXFLTR_SIZE, NULL)) != 0) {
471					return (c);
472				}
473				break;
474			case 'd':
475				/*
476				 * Translate --dynamic-linker <optarg> to
477				 * -I <optarg>
478				 */
479				if ((c = str2chr(lml, ndx, argc, argv, arg, 'I',
480				    MSG_ORIG(MSG_ARG_T_INTERP),
481				    MSG_ARG_T_INTERP_SIZE, NULL)) != 0) {
482					return (c);
483				}
484				break;
485			case 'e':
486				/* Translate --entry <optarg> to -e <optarg> */
487				if ((c = str2chr(lml, ndx, argc, argv, arg, 'e',
488				    MSG_ORIG(MSG_ARG_T_ENTRY),
489				    MSG_ARG_T_ENTRY_SIZE, NULL)) != 0) {
490					return (c);
491				}
492				/*
493				 * Translate --end-group to -z rescan-end
494				 */
495				if ((c = str2chr(lml, ndx, argc, argv,
496				    arg, 'z', MSG_ORIG(MSG_ARG_T_ENDGROUP),
497				    0, NULL)) != 0) {
498					optarg = (char *)
499					    MSG_ORIG(MSG_ARG_RESCAN_END);
500					return (c);
501				}
502				break;
503			case 'f':
504				/*
505				 * Translate --fatal-warnings to
506				 * -z fatal-warnings.
507				 */
508				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
509				    MSG_ORIG(MSG_ARG_T_FATWARN),
510				    0, NULL)) != 0) {
511					optarg = (char *)
512					    MSG_ORIG(MSG_ARG_FATWARN);
513					return (c);
514				}
515				/* Translate --filter <optarg> to -F <optarg> */
516				if ((c = str2chr(lml, ndx, argc, argv, arg, 'F',
517				    MSG_ORIG(MSG_ARG_T_STDFLTR),
518				    MSG_ARG_T_STDFLTR_SIZE, NULL)) != 0) {
519					return (c);
520				}
521				break;
522			case 'h':
523				/* Translate --help to -zhelp */
524				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
525				    MSG_ORIG(MSG_ARG_T_HELP), 0, NULL)) !=
526				    0) {
527					optarg = (char *)MSG_ORIG(MSG_ARG_HELP);
528					return (c);
529				}
530				break;
531			case 'l':
532				/*
533				 * Translate --library <optarg> to -l <optarg>
534				 */
535				if ((c = str2chr(lml, ndx, argc, argv, arg, 'l',
536				    MSG_ORIG(MSG_ARG_T_LIBRARY),
537				    MSG_ARG_T_LIBRARY_SIZE, NULL)) != 0) {
538					return (c);
539
540				/*
541				 * Translate --library-path <optarg> to
542				 * -L <optarg>
543				 */
544				} else if ((c = str2chr(lml, ndx, argc, argv,
545				    arg, 'L', MSG_ORIG(MSG_ARG_T_LIBPATH),
546				    MSG_ARG_T_LIBPATH_SIZE, NULL)) != 0) {
547					return (c);
548				}
549				break;
550			case 'n':
551				/*
552				 * Translate --no-fatal-warnings to
553				 * -z nofatal-warnings.
554				 */
555				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
556				    MSG_ORIG(MSG_ARG_T_NOFATWARN),
557				    0, NULL)) != 0) {
558					optarg = (char *)
559					    MSG_ORIG(MSG_ARG_NOFATWARN);
560					return (c);
561				}
562
563				/* Translate --no-undefined to -zdefs */
564				if ((c = str2chr(lml, ndx, argc, argv, arg, 'z',
565				    MSG_ORIG(MSG_ARG_T_NOUNDEF), 0, NULL)) !=
566				    0) {
567					optarg = (char *)MSG_ORIG(MSG_ARG_DEFS);
568					return (c);
569
570				/*
571				 * Translate --no-whole-archive to
572				 * -z defaultextract
573				 */
574				} else if ((c = str2chr(lml, ndx, argc, argv,
575				    arg, 'z', MSG_ORIG(MSG_ARG_T_NOWHOLEARC),
576				    0, NULL)) != 0) {
577					optarg =
578					    (char *)MSG_ORIG(MSG_ARG_DFLEXTRT);
579					return (c);
580				}
581				break;
582			case 'o':
583				/* Translate --output <optarg> to -o <optarg> */
584				if ((c = str2chr(lml, ndx, argc, argv, arg, 'o',
585				    MSG_ORIG(MSG_ARG_T_OUTPUT),
586				    MSG_ARG_T_OUTPUT_SIZE, NULL)) != 0) {
587					return (c);
588				}
589				break;
590			case 'r':
591				/* Translate --relocatable to -r */
592				if ((c = str2chr(lml, ndx, argc, argv, arg, 'r',
593				    MSG_ORIG(MSG_ARG_T_RELOCATABLE), 0,
594				    NULL)) != 0) {
595					return (c);
596				}
597				break;
598			case 's':
599				/* Translate --strip-all to -s */
600				if ((c = str2chr(lml, ndx, argc, argv, arg, 's',
601				    MSG_ORIG(MSG_ARG_T_STRIP), 0, NULL)) !=
602				    0) {
603					return (c);
604				}
605				/*
606				 * Translate --start-group to -z rescan-start
607				 */
608				if ((c = str2chr(lml, ndx, argc, argv,
609				    arg, 'z', MSG_ORIG(MSG_ARG_T_STARTGROUP),
610				    0, NULL)) != 0) {
611					optarg = (char *)
612					    MSG_ORIG(MSG_ARG_RESCAN_START);
613					return (c);
614				}
615				break;
616			case 'u':
617				/*
618				 * Translate --undefined <optarg> to
619				 * -u <optarg>
620				 */
621				if ((c = str2chr(lml, ndx, argc, argv, arg, 'u',
622				    MSG_ORIG(MSG_ARG_T_UNDEF),
623				    MSG_ARG_T_UNDEF_SIZE, NULL)) != 0) {
624					return (c);
625				}
626				break;
627			case 'v':
628				/* Translate --version to -V */
629				if ((c = str2chr(lml, ndx, argc, argv, arg, 'V',
630				    MSG_ORIG(MSG_ARG_T_VERSION), 0, NULL)) !=
631				    0) {
632					return (c);
633				}
634				break;
635			case 'w':
636				/*
637				 * Translate --whole-archive to -z alltextract
638				 */
639				if ((c = str2chr(lml, ndx, argc, argv,
640				    arg, 'z', MSG_ORIG(MSG_ARG_T_WHOLEARC),
641				    0, NULL)) != 0) {
642					optarg =
643					    (char *)MSG_ORIG(MSG_ARG_ALLEXTRT);
644					return (c);
645				}
646				/*
647				 * Translate --wrap to -z wrap=
648				 */
649				if ((c = str2chr(lml, ndx, argc, argv,
650				    arg, 'z', MSG_ORIG(MSG_ARG_T_WRAP),
651				    MSG_ARG_T_WRAP_SIZE, str2chr_wrap_cb)) !=
652				    0) {
653					return (c);
654				}
655				break;
656			}
657			break;
658		}
659	}
660
661	if ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != -1) {
662		/*
663		 * It is possible that a "-Wl," argument has been used to
664		 * specify an option.  This isn't advertized ld(1) syntax, but
665		 * compiler drivers and configuration tools, have been known to
666		 * pass this compiler option to ld(1).  Strip off the "-Wl,"
667		 * prefix and pass the option through.
668		 */
669		if ((c == 'W') && (strncmp(optarg,
670		    MSG_ORIG(MSG_ARG_T_WL), MSG_ARG_T_WL_SIZE) == 0)) {
671			DBG_CALL(Dbg_args_Wldel(lml, ndx, optarg));
672			c = optarg[MSG_ARG_T_WL_SIZE];
673			optarg += MSG_ARG_T_WL_SIZE + 1;
674		}
675	}
676
677	return (c);
678}
679
680/*
681 * A compare routine for Isd_node AVL trees.
682 */
683int
684isdavl_compare(const void *n1, const void *n2)
685{
686	uint_t		hash1, hash2;
687	const char	*st1, *st2;
688	int		rc;
689
690	hash1 = ((Isd_node *)n1)->isd_hash;
691	hash2 = ((Isd_node *)n2)->isd_hash;
692
693	if (hash1 > hash2)
694		return (1);
695	if (hash1 < hash2)
696		return (-1);
697
698	st1 = ((Isd_node *)n1)->isd_name;
699	st2 = ((Isd_node *)n2)->isd_name;
700
701	rc = strcmp(st1, st2);
702	if (rc > 0)
703		return (1);
704	if (rc < 0)
705		return (-1);
706	return (0);
707}
708
709/*
710 * Messaging support - funnel everything through dgettext().
711 */
712const char *
713_libld_msg(Msg mid)
714{
715	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
716}
717
718/*
719 * Determine whether a symbol name should be demangled.
720 */
721const char *
722demangle(const char *name)
723{
724	if (demangle_flag)
725		return (Elf_demangle_name(name));
726	else
727		return (name);
728}
729
730/*
731 * Compare a series of platform or machine hardware names.
732 */
733int
734cap_names_match(Alist *alp1, Alist *alp2)
735{
736	Capstr		*capstr1;
737	Aliste		idx1;
738	int		match = 0;
739	Word		nitems;
740
741	if ((nitems = alist_nitems(alp1)) != alist_nitems(alp2))
742		return (1);
743
744	for (ALIST_TRAVERSE(alp1, idx1, capstr1)) {
745		Capstr		*capstr2;
746		Aliste 		idx2;
747
748		for (ALIST_TRAVERSE(alp2, idx2, capstr2)) {
749			if (strcmp(capstr1->cs_str, capstr2->cs_str))
750				continue;
751
752			match++;
753			break;
754		}
755	}
756
757	if (nitems == match)
758		return (0);
759
760	return (1);
761}
762