xref: /illumos-gate/usr/src/cmd/sgs/libld/common/util.c (revision dd72704bd9e794056c558153663c739e2012d721)
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