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 */
91static void *
92dz_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
106void *
107libld_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
156void *
157libld_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
183void
184/* ARGSUSED 0 */
185libld_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 */
215Sdf_desc *
216sdf_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
228Sdf_desc *
229sdf_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 */
249char *
250add_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 */
293static int
294str2chr_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 */
324static int
325str2chr(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 */
403int
404ld_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 */
696int
697isdavl_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 */
725const 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 */
734const char *
735demangle(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 */
746int
747cap_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}
775