xref: /illumos-gate/usr/src/cmd/sgs/libld/common/util.c (revision 66e150d7d3c0cb2de3c45c74612784ffd3e73de6)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *	Copyright (c) 1988 AT&T
29  *	  All Rights Reserved
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 /*
35  * Utility functions
36  */
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <sys/types.h>
43 #include <sys/mman.h>
44 #include <errno.h>
45 #include <sgs.h>
46 #include <libintl.h>
47 #include <debug.h>
48 #include "msg.h"
49 #include "_libld.h"
50 
51 /*
52  * libld_malloc() and dz_map() are used for both performance and for ease of
53  * programming:
54  *
55  * Performance:
56  *	The link-edit is a short lived process which doesn't really free much
57  *	of the dynamic memory that it requests.  Because of this, it is more
58  *	important to optimize for quick memory allocations than the
59  *	re-usability of the memory.
60  *
61  *	By also mmaping blocks of pages in from /dev/zero we don't need to
62  *	waste the overhead of zeroing out these pages for calloc() requests.
63  *
64  * Memory Management:
65  *	By doing all libld memory management through the ld_malloc routine
66  *	it's much easier to free up all memory at the end by simply unmaping
67  *	all of the blocks that were mapped in through dz_map().  This is much
68  *	simpler then trying to track all of the libld structures that were
69  *	dynamically allocate and are actually pointers into the ELF files.
70  *
71  *	It's important that we can free up all of our dynamic memory because
72  *	libld is used by ld.so.1 when it performs dlopen()'s of relocatable
73  *	objects.
74  *
75  * Format:
76  *	The memory blocks for each allocation store the size of the allocation
77  *	in the first 8 bytes of the block.  The pointer that is returned by
78  *	libld_malloc() is actually the address of (block + 8):
79  *
80  *		(addr - 8)	block_size
81  *		(addr)		<allocated block>
82  *
83  *	The size is retained in order to implement realloc(), and to perform
84  *	the required memcpy().  8 bytes are uses, as the memory area returned
85  *	by libld_malloc() must be 8 byte-aligned.  Even in a 32-bit environment,
86  *	u_longlog_t pointers are employed.
87  *
88  * MAP_ANON arrived in Solaris 8, thus a fall-back is provided for older
89  * systems.
90  */
91 static void *
92 dz_map(size_t size)
93 {
94 	void	*addr;
95 	int	err;
96 
97 #if	defined(MAP_ANON)
98 	static int	noanon = 0;
99 
100 	if (noanon == 0) {
101 		if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC),
102 		    (MAP_PRIVATE | MAP_ANON), -1, 0)) != MAP_FAILED)
103 			return (addr);
104 
105 		if ((errno != EBADF) && (errno != EINVAL)) {
106 			err = errno;
107 			eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON),
108 			    MSG_ORIG(MSG_PTH_DEVZERO), strerror(err));
109 			return (MAP_FAILED);
110 		} else
111 			noanon = 1;
112 	}
113 #endif
114 	if (dz_fd == -1) {
115 		if ((dz_fd = open(MSG_ORIG(MSG_PTH_DEVZERO), O_RDONLY)) == -1) {
116 			err = errno;
117 			eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
118 			    MSG_ORIG(MSG_PTH_DEVZERO), strerror(err));
119 			return (MAP_FAILED);
120 		}
121 	}
122 
123 	if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC),
124 	    MAP_PRIVATE, dz_fd, 0)) == MAP_FAILED) {
125 		err = errno;
126 		eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_MMAP),
127 		    MSG_ORIG(MSG_PTH_DEVZERO), strerror(err));
128 		return (MAP_FAILED);
129 	}
130 	return (addr);
131 }
132 
133 void *
134 libld_malloc(size_t size)
135 {
136 	Ld_heap		*chp = ld_heap;
137 	void		*vptr;
138 	size_t		asize = size + HEAPALIGN;
139 
140 	/*
141 	 * If this is the first allocation, or the allocation request is greater
142 	 * than the current free space available, allocate a new heap.
143 	 */
144 	if ((chp == 0) ||
145 	    (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) {
146 		Ld_heap	*nhp;
147 		size_t	hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN);
148 		size_t	tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN);
149 
150 		/*
151 		 * Allocate a block that is at minimum 'HEAPBLOCK' size
152 		 */
153 		if (tsize < HEAPBLOCK)
154 			tsize = HEAPBLOCK;
155 
156 		if ((nhp = dz_map(tsize)) == MAP_FAILED)
157 			return (0);
158 
159 		nhp->lh_next = chp;
160 		nhp->lh_free = (void *)((size_t)nhp + hsize);
161 		nhp->lh_end = (void *)((size_t)nhp + tsize);
162 
163 		ld_heap = chp = nhp;
164 	}
165 	vptr = chp->lh_free;
166 
167 	/*
168 	 * Assign size to head of allocated block (used by realloc), and
169 	 * memory arena as then next 8-byte aligned offset.
170 	 */
171 	*((size_t *)vptr) = size;
172 	vptr = (void *)((size_t)vptr + HEAPALIGN);
173 
174 	/*
175 	 * Increment free to point to next available block
176 	 */
177 	chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize,
178 	    HEAPALIGN);
179 
180 	return (vptr);
181 }
182 
183 void *
184 libld_realloc(void *ptr, size_t size)
185 {
186 	size_t	psize;
187 	void	*vptr;
188 
189 	if (ptr == NULL)
190 		return (libld_malloc(size));
191 
192 	/*
193 	 * Size of the allocated blocks is stored *just* before the blocks
194 	 * address.
195 	 */
196 	psize = *((size_t *)((size_t)ptr - HEAPALIGN));
197 
198 	/*
199 	 * If the block actually fits then just return.
200 	 */
201 	if (size <= psize)
202 		return (ptr);
203 
204 	if ((vptr = libld_malloc(size)) != 0)
205 		(void) memcpy(vptr, ptr, psize);
206 
207 	return (vptr);
208 }
209 
210 void
211 /* ARGSUSED 0 */
212 libld_free(void *ptr)
213 {
214 }
215 
216 /*
217  * Append an item to the specified list, and return a pointer to the list
218  * node created.
219  */
220 Listnode *
221 list_appendc(List *lst, const void *item)
222 {
223 	Listnode	*_lnp;
224 
225 	if ((_lnp = libld_malloc(sizeof (Listnode))) == 0)
226 		return (0);
227 
228 	_lnp->data = (void *)item;
229 	_lnp->next = NULL;
230 
231 	if (lst->head == NULL)
232 		lst->tail = lst->head = _lnp;
233 	else {
234 		lst->tail->next = _lnp;
235 		lst->tail = lst->tail->next;
236 	}
237 	return (_lnp);
238 }
239 
240 /*
241  * Add an item after the specified listnode, and return a pointer to the list
242  * node created.
243  */
244 Listnode *
245 list_insertc(List *lst, const void *item, Listnode *lnp)
246 {
247 	Listnode	*_lnp;
248 
249 	if ((_lnp = libld_malloc(sizeof (Listnode))) == 0)
250 		return (0);
251 
252 	_lnp->data = (void *)item;
253 	_lnp->next = lnp->next;
254 	if (_lnp->next == NULL)
255 		lst->tail = _lnp;
256 	lnp->next = _lnp;
257 	return (_lnp);
258 }
259 
260 /*
261  * Prepend an item to the specified list, and return a pointer to the
262  * list node created.
263  */
264 Listnode *
265 list_prependc(List *lst, const void *item)
266 {
267 	Listnode	*_lnp;
268 
269 	if ((_lnp = libld_malloc(sizeof (Listnode))) == 0)
270 		return (0);
271 
272 	_lnp->data = (void *)item;
273 
274 	if (lst->head == NULL) {
275 		_lnp->next = NULL;
276 		lst->tail = lst->head = _lnp;
277 	} else {
278 		_lnp->next = lst->head;
279 		lst->head = _lnp;
280 	}
281 	return (_lnp);
282 }
283 
284 /*
285  * Find out where to insert the node for reordering.  List of insect structures
286  * is traversed and the is_txtndx field of the insect structure is examined
287  * and that determines where the new input section should be inserted.
288  * All input sections which have a non zero is_txtndx value will be placed
289  * in ascending order before sections with zero is_txtndx value.  This
290  * implies that any section that does not appear in the map file will be
291  * placed at the end of this list as it will have a is_txtndx value of 0.
292  * Returns:  NULL if the input section should be inserted at beginning
293  * of list else A pointer to the entry AFTER which this new section should
294  * be inserted.
295  */
296 Listnode *
297 list_where(List *lst, Word num)
298 {
299 	Listnode	*ln, *pln;	/* Temp list node ptr */
300 	Is_desc		*isp;		/* Temp Insect structure */
301 	Word		n;
302 
303 	/*
304 	 * No input sections exist, so add at beginning of list
305 	 */
306 	if (lst->head == NULL)
307 		return (NULL);
308 
309 	for (ln = lst->head, pln = ln; ln != NULL; pln = ln, ln = ln->next) {
310 		isp = (Is_desc *)ln->data;
311 		/*
312 		 *  This should never happen, but if it should we
313 		 *  try to do the right thing.  Insert at the
314 		 *  beginning of list if no other items exist, else
315 		 *  end of already existing list, prior to this null
316 		 *  item.
317 		 */
318 		if (isp == NULL) {
319 			if (ln == pln) {
320 				return (NULL);
321 			} else {
322 				return (pln);
323 			}
324 		}
325 		/*
326 		 *  We have reached end of reorderable items.  All
327 		 *  following items have is_txtndx values of zero
328 		 *  So insert at end of reorderable items.
329 		 */
330 		if ((n = isp->is_txtndx) > num || n == 0) {
331 			if (ln == pln) {
332 				return (NULL);
333 			} else {
334 				return (pln);
335 			}
336 		}
337 		/*
338 		 *  We have reached end of list, so insert
339 		 *  at the end of this list.
340 		 */
341 		if ((n != 0) && (ln->next == NULL))
342 			return (ln);
343 	}
344 	return (NULL);
345 }
346 
347 /*
348  * Determine if a shared object definition structure already exists and if
349  * not create one.  These definitions provide for recording information
350  * regarding shared objects that are still to be processed.  Once processed
351  * shared objects are maintained on the ofl_sos list.  The information
352  * recorded in this structure includes:
353  *
354  *  o	DT_USED requirements.  In these cases definitions are added during
355  *	mapfile processing of `-' entries (see map_dash()).
356  *
357  *  o	implicit NEEDED entries.  As shared objects are processed from the
358  *	command line so any of their dependencies are recorded in these
359  *	structures for later processing (see process_dynamic()).
360  *
361  *  o	version requirements.  Any explicit shared objects that have version
362  *	dependencies on other objects have their version requirements recorded.
363  *	In these cases definitions are added during mapfile processing of `-'
364  *	entries (see map_dash()).  Also, shared objects may have versioning
365  *	requirements on their NEEDED entries.  These cases are added during
366  *	their version processing (see vers_need_process()).
367  *
368  *	Note: Both process_dynamic() and vers_need_process() may generate the
369  *	initial version definition structure because you can't rely on what
370  *	section (.dynamic or .SUNW_version) may be processed first from	any
371  *	input file.
372  */
373 Sdf_desc *
374 sdf_find(const char *name, List *lst)
375 {
376 	Listnode	*lnp;
377 	Sdf_desc	*sdf;
378 
379 	for (LIST_TRAVERSE(lst, lnp, sdf))
380 		if (strcmp(name, sdf->sdf_name) == 0)
381 			return (sdf);
382 
383 	return (0);
384 }
385 
386 Sdf_desc *
387 sdf_add(const char *name, List *lst)
388 {
389 	Sdf_desc	*sdf;
390 
391 	if (!(sdf = libld_calloc(sizeof (Sdf_desc), 1)))
392 		return ((Sdf_desc *)S_ERROR);
393 
394 	sdf->sdf_name = name;
395 
396 	if (list_appendc(lst, sdf) == 0)
397 		return ((Sdf_desc *)S_ERROR);
398 	else
399 		return (sdf);
400 }
401 
402 /*
403  * Add a string, separated by a colon, to an existing string.  Typically used
404  * to maintain filter, rpath and audit names, of which there is normally only
405  * one string supplied anyway.
406  */
407 char *
408 add_string(char *old, char *str)
409 {
410 	char	*new;
411 
412 	if (old) {
413 		char	*_str;
414 		size_t	len;
415 
416 		/*
417 		 * If an original string exists, make sure this new string
418 		 * doesn't get duplicated.
419 		 */
420 		if ((_str = strstr(old, str)) != NULL) {
421 			if (((_str == old) ||
422 			    (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) &&
423 			    (_str += strlen(str)) &&
424 			    ((*_str == '\0') ||
425 			    (*_str == *(MSG_ORIG(MSG_STR_COLON)))))
426 				return (old);
427 		}
428 
429 		len = strlen(old) + strlen(str) + 2;
430 		if ((new = libld_calloc(1, len)) == 0)
431 			return ((char *)S_ERROR);
432 		(void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str);
433 	} else {
434 		if ((new = libld_malloc(strlen(str) + 1)) == 0)
435 			return ((char *)S_ERROR);
436 		(void) strcpy(new, str);
437 	}
438 
439 	return (new);
440 }
441 
442 /*
443  * Messaging support - funnel everything through dgettext().
444  */
445 
446 const char *
447 _libld_msg(Msg mid)
448 {
449 	return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
450 }
451 
452 /*
453  * Determine whether a symbol name should be demangled.
454  */
455 const char *
456 demangle(const char *name)
457 {
458 	if (demangle_flag)
459 		return (Elf_demangle_name(name));
460 	else
461 		return (name);
462 }
463