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