xref: /illumos-gate/usr/src/cmd/sgs/libcrle/common/dump.c (revision fec04708)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
235aefb655Srie  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include	<sys/mman.h>
287c478bd9Sstevel@tonic-gate #include	<sys/types.h>
297c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
307c478bd9Sstevel@tonic-gate #include	<procfs.h>
317c478bd9Sstevel@tonic-gate #include	<unistd.h>
327c478bd9Sstevel@tonic-gate #include	<fcntl.h>
337c478bd9Sstevel@tonic-gate #include	<stdio.h>
347c478bd9Sstevel@tonic-gate #include	<string.h>
357c478bd9Sstevel@tonic-gate #include	<limits.h>
367c478bd9Sstevel@tonic-gate #include	<errno.h>
377c478bd9Sstevel@tonic-gate #include	<alloca.h>
387c478bd9Sstevel@tonic-gate #include	"rtld.h"
397c478bd9Sstevel@tonic-gate #include	"rtc.h"
407c478bd9Sstevel@tonic-gate #include	"_crle.h"
417c478bd9Sstevel@tonic-gate #include	"msg.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Routines for dumping alternate objects under CRLE_AUD_DLDUMP mode.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate static Addr	membgn = 0;
477c478bd9Sstevel@tonic-gate static Addr	memend = 0;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * For each file in the configuration file that requires an alternate (dldump())
517c478bd9Sstevel@tonic-gate  * version, add the object to the processes main link-map.  The process head
527c478bd9Sstevel@tonic-gate  * may be an application, shared object, or lddstub.  In any case this object
537c478bd9Sstevel@tonic-gate  * may be augmented with other objects defined within the configuration file.
547c478bd9Sstevel@tonic-gate  *
557c478bd9Sstevel@tonic-gate  * Each file is initially loaded with RTLD_CONFGEN so that no dependency
567c478bd9Sstevel@tonic-gate  * analysis, relocation, or user code (.init's) is executed.  By skipping
577c478bd9Sstevel@tonic-gate  * analysis we save time and allow for a family of objects to be dumped that
587c478bd9Sstevel@tonic-gate  * may not have all relocations satisfied.  If necessary, a later call to
597c478bd9Sstevel@tonic-gate  * dlopen() using RTLD_NOW will force relocations to occur.
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * A mapping range is maintained to span the mapping of each objects, and this
627c478bd9Sstevel@tonic-gate  * range is finally written back to the caller.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate static int
657c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
load(const char * opath,const char * npath)667c478bd9Sstevel@tonic-gate load(const char *opath, const char *npath)
677c478bd9Sstevel@tonic-gate {
687c478bd9Sstevel@tonic-gate 	Grp_hdl *	ghp;
697c478bd9Sstevel@tonic-gate 	Rt_map *	lmp;
707c478bd9Sstevel@tonic-gate 	Addr		_membgn, _memend;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	if ((ghp = (Grp_hdl *)dlmopen(LM_ID_BASE, opath,
737c478bd9Sstevel@tonic-gate 	    (RTLD_LAZY | RTLD_GLOBAL | RTLD_CONFGEN))) == NULL) {
747c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_DL_OPEN),
757c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), dlerror());
767c478bd9Sstevel@tonic-gate 		return (1);
777c478bd9Sstevel@tonic-gate 	}
785aefb655Srie 	lmp = ghp->gh_ownlmp;
797c478bd9Sstevel@tonic-gate 	FLAGS1(lmp) |= FL1_RT_CONFSET;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	/*
827c478bd9Sstevel@tonic-gate 	 * Establish the mapping range of the objects dumped so far.
837c478bd9Sstevel@tonic-gate 	 */
847c478bd9Sstevel@tonic-gate 	_membgn = ADDR(lmp);
857c478bd9Sstevel@tonic-gate 	_memend = (ADDR(lmp) + MSIZE(lmp));
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	if (membgn == 0) {
887c478bd9Sstevel@tonic-gate 		membgn = _membgn;
897c478bd9Sstevel@tonic-gate 		memend = _memend;
907c478bd9Sstevel@tonic-gate 	} else {
917c478bd9Sstevel@tonic-gate 		if (membgn > _membgn)
927c478bd9Sstevel@tonic-gate 			membgn = _membgn;
937c478bd9Sstevel@tonic-gate 		if (memend < _memend)
947c478bd9Sstevel@tonic-gate 			memend = _memend;
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 	return (0);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * dldump(3x) an object that is already part of the main link-map list.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate static int
dump(const char * opath,const char * npath)1037c478bd9Sstevel@tonic-gate dump(const char *opath, const char *npath)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	(void) unlink(npath);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	if (dldump(opath, npath, dlflag) != 0) {
1087c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_DL_DUMP),
1097c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), dlerror());
1107c478bd9Sstevel@tonic-gate 		return (1);
1117c478bd9Sstevel@tonic-gate 	}
1127c478bd9Sstevel@tonic-gate 	return (0);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Traverse a configuration file directory/file list.  Each file within the
1177c478bd9Sstevel@tonic-gate  * list is maintained as both a full pathname and a simple filename - we're
1187c478bd9Sstevel@tonic-gate  * only interested in one.
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * This rutine is called twice, once to insure the appropriate objects are
1217c478bd9Sstevel@tonic-gate  * mapped in (fptr == load()) and then once again to dldump(3x) the mapped
1227c478bd9Sstevel@tonic-gate  * objects (fptr == dump()).
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static int
scanconfig(Addr addr,int (* fptr)())1257c478bd9Sstevel@tonic-gate scanconfig(Addr addr, int (*fptr)())
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	Rtc_head *	head = (Rtc_head *)addr;
1287c478bd9Sstevel@tonic-gate 	Rtc_obj *	obj;
1297c478bd9Sstevel@tonic-gate 	Rtc_dir *	dirtbl;
1307c478bd9Sstevel@tonic-gate 	Rtc_file *	filetbl;
1317c478bd9Sstevel@tonic-gate 	const char	*str, *strtbl;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	/* LINTED */
1347c478bd9Sstevel@tonic-gate 	strtbl = (const char *)((char *)addr + head->ch_str);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	/*
1377c478bd9Sstevel@tonic-gate 	 * Scan the directory and filename arrays looking for alternatives.
1387c478bd9Sstevel@tonic-gate 	 */
1397c478bd9Sstevel@tonic-gate 	for (dirtbl = (Rtc_dir *)(head->ch_dir + addr);
1407c478bd9Sstevel@tonic-gate 	    dirtbl->cd_obj; dirtbl++) {
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		obj = (Rtc_obj *)(dirtbl->cd_obj + addr);
1437c478bd9Sstevel@tonic-gate 		str = strtbl + obj->co_name;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 		if (obj->co_flags & RTC_OBJ_NOEXIST)
1467c478bd9Sstevel@tonic-gate 			continue;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		for (filetbl = (Rtc_file *)(dirtbl->cd_file + addr);
1497c478bd9Sstevel@tonic-gate 		    filetbl->cf_obj; filetbl++) {
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 			obj = (Rtc_obj *)(filetbl->cf_obj + addr);
1527c478bd9Sstevel@tonic-gate 			str = strtbl + obj->co_name;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 			if ((obj->co_flags &
1557c478bd9Sstevel@tonic-gate 			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH | RTC_OBJ_EXEC)) ==
1567c478bd9Sstevel@tonic-gate 			    (RTC_OBJ_DUMP | RTC_OBJ_REALPTH)) {
1577c478bd9Sstevel@tonic-gate 				if ((*fptr)(str, strtbl + obj->co_alter) != 0)
1587c478bd9Sstevel@tonic-gate 					return (1);
1597c478bd9Sstevel@tonic-gate 			}
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Are we dumping a specific application.
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	if (head->ch_app) {
1677c478bd9Sstevel@tonic-gate 		if (fptr == load) {
1687c478bd9Sstevel@tonic-gate 			Grp_hdl *	ghp;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 			/*
1717c478bd9Sstevel@tonic-gate 			 * Obtain a handle to the application and set the
1727c478bd9Sstevel@tonic-gate 			 * FL1_RT_CONFSET flag.
1737c478bd9Sstevel@tonic-gate 			 */
1747c478bd9Sstevel@tonic-gate 			if ((ghp = dlmopen(LM_ID_BASE, 0,
1757c478bd9Sstevel@tonic-gate 			    (RTLD_NOLOAD | RTLD_CONFGEN))) == 0)
1767c478bd9Sstevel@tonic-gate 				return (1);
1775aefb655Srie 			FLAGS1(ghp->gh_ownlmp) |= FL1_RT_CONFSET;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		} else {
1807c478bd9Sstevel@tonic-gate 			/*
1817c478bd9Sstevel@tonic-gate 			 * If we're dumping and this configuration is for a
1827c478bd9Sstevel@tonic-gate 			 * specific application dump it also.
1837c478bd9Sstevel@tonic-gate 			 */
1847c478bd9Sstevel@tonic-gate 			/* LINTED */
1857c478bd9Sstevel@tonic-gate 			obj = (Rtc_obj *)((char *)addr + head->ch_app);
1867c478bd9Sstevel@tonic-gate 			str = strtbl + obj->co_alter;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 			if (dump((const char *)0, str) != 0)
1897c478bd9Sstevel@tonic-gate 				return (1);
1907c478bd9Sstevel@tonic-gate 		}
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	return (0);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * Before loading any dependencies determine the present memory mappings being
1987c478bd9Sstevel@tonic-gate  * used and fill any holes between these mappings.  This insures that all
1997c478bd9Sstevel@tonic-gate  * dldump()'ed dependencies will live in a single consecutive address range.
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate int
filladdr(void)2027c478bd9Sstevel@tonic-gate filladdr(void)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	prmap_t		*maps, *_maps;
2057c478bd9Sstevel@tonic-gate 	struct stat	status;
2067c478bd9Sstevel@tonic-gate 	int		fd = 0, err, num, _num;
2077c478bd9Sstevel@tonic-gate 	size_t		size, syspagsz;
2087c478bd9Sstevel@tonic-gate 	uintptr_t	laddr = 0, saddr;
2097c478bd9Sstevel@tonic-gate 	pstatus_t	prstatus;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/*
2127c478bd9Sstevel@tonic-gate 	 * Open /proc/self/status to determine the virtual address of the
2137c478bd9Sstevel@tonic-gate 	 * process heap.
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 	if ((fd = open(MSG_ORIG(MSG_PTH_PROCSTATUS), O_RDONLY)) == -1) {
2167c478bd9Sstevel@tonic-gate 		err = errno;
2177c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
2187c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), MSG_ORIG(MSG_PTH_PROCSTATUS),
2197c478bd9Sstevel@tonic-gate 		    strerror(err));
2207c478bd9Sstevel@tonic-gate 		return (1);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 	if (read(fd, &prstatus, sizeof (pstatus_t)) != sizeof (pstatus_t)) {
2237c478bd9Sstevel@tonic-gate 		err = errno;
2247c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ),
2257c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), MSG_ORIG(MSG_PTH_PROCSTATUS),
2267c478bd9Sstevel@tonic-gate 		    strerror(err));
2277c478bd9Sstevel@tonic-gate 		(void) close(fd);
2287c478bd9Sstevel@tonic-gate 		return (1);
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	(void) close(fd);
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/*
2337c478bd9Sstevel@tonic-gate 	 * Round the process heap to the next page boundary so that it can be
234*fec04708SRichard Lowe 	 * used to isolated the executable's mappings (pr_brkbase typically
235*fec04708SRichard Lowe 	 * occurs at the end, but within, the executable's data segment).  As
236*fec04708SRichard Lowe 	 * libcrle is used as an audit library, no process user code has run
237*fec04708SRichard Lowe 	 * so there can't be any heap. pr_brksize is added here for
238*fec04708SRichard Lowe 	 * completeness.
2397c478bd9Sstevel@tonic-gate 	 */
2407c478bd9Sstevel@tonic-gate 	syspagsz = sysconf(_SC_PAGESIZE);
2417c478bd9Sstevel@tonic-gate 	saddr = M_PROUND(prstatus.pr_brkbase + prstatus.pr_brksize);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * Open /proc/self/rmap to obtain the processes reserved mappings.
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	if ((fd = open(MSG_ORIG(MSG_PTH_PROCRMAP), O_RDONLY)) == -1) {
2477c478bd9Sstevel@tonic-gate 		err = errno;
2487c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
2497c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), MSG_ORIG(MSG_PTH_PROCRMAP),
2507c478bd9Sstevel@tonic-gate 		    strerror(err));
2517c478bd9Sstevel@tonic-gate 		return (1);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	(void) fstat(fd, &status);
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	/*
2567c478bd9Sstevel@tonic-gate 	 * Determine number of mappings - use alloca so as not to perturb any
2577c478bd9Sstevel@tonic-gate 	 * mapping information by a malloc, which itself might add a mapping.
2587c478bd9Sstevel@tonic-gate 	 */
2597c478bd9Sstevel@tonic-gate 	/* LINTED */
2607c478bd9Sstevel@tonic-gate 	num = (int)(status.st_size / sizeof (prmap_t));
2617c478bd9Sstevel@tonic-gate 	size = num * sizeof (prmap_t);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if ((maps = alloca(size)) == 0) {
2647c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_ALLOC),
2657c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), strerror(ENOMEM));
2667c478bd9Sstevel@tonic-gate 		(void) close(pfd);
2677c478bd9Sstevel@tonic-gate 		return (1);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (read(fd, (void *)maps, size) < 0) {
2717c478bd9Sstevel@tonic-gate 		err = errno;
2727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_READ),
2737c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), MSG_ORIG(MSG_PTH_PROCRMAP),
2747c478bd9Sstevel@tonic-gate 		    strerror(err));
2757c478bd9Sstevel@tonic-gate 		(void) close(fd);
2767c478bd9Sstevel@tonic-gate 		return (1);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	(void) close(fd);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	/*
2817c478bd9Sstevel@tonic-gate 	 * Use /dev/null for filling holes.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	if ((fd = open(MSG_ORIG(MSG_PTH_DEVNULL), O_RDONLY)) == -1) {
2847c478bd9Sstevel@tonic-gate 		err = errno;
2857c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
2867c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), MSG_ORIG(MSG_PTH_DEVNULL),
2877c478bd9Sstevel@tonic-gate 		    strerror(err));
2887c478bd9Sstevel@tonic-gate 		return (1);
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * Scan each mapping - note it is assummed that the mappings are
2937c478bd9Sstevel@tonic-gate 	 * presented in order.  We fill holes between mappings.  On intel
2947c478bd9Sstevel@tonic-gate 	 * the last mapping is usually the data segment of ld.so.1, after
2957c478bd9Sstevel@tonic-gate 	 * this comes a red zone into which non-fixed mapping won't get
2967c478bd9Sstevel@tonic-gate 	 * place.  Thus we can simply bail from the loop after seeing the
2977c478bd9Sstevel@tonic-gate 	 * last mapping.
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate 	for (_num = 0, _maps = maps; _num < num; _num++, _maps++) {
3007c478bd9Sstevel@tonic-gate 		/*
301*fec04708SRichard Lowe 		 * Skip all mappings below brkbase, these represent the
302*fec04708SRichard Lowe 		 * executable (and the stack on intel).
3037c478bd9Sstevel@tonic-gate 		 */
3047c478bd9Sstevel@tonic-gate 		if ((laddr == 0) &&
3057c478bd9Sstevel@tonic-gate 		    ((_maps->pr_vaddr + _maps->pr_size) <= saddr))
3067c478bd9Sstevel@tonic-gate 			continue;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 		/*
3097c478bd9Sstevel@tonic-gate 		 * For each consecutive mapping determine the hole between each
3107c478bd9Sstevel@tonic-gate 		 * and fill it from /dev/null.
3117c478bd9Sstevel@tonic-gate 		 */
3127c478bd9Sstevel@tonic-gate 		if (laddr == 0) {
3137c478bd9Sstevel@tonic-gate 			laddr = _maps->pr_vaddr + _maps->pr_size;
3147c478bd9Sstevel@tonic-gate 			continue;
3157c478bd9Sstevel@tonic-gate 		}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		if ((size = _maps->pr_vaddr - laddr) != 0) {
3187c478bd9Sstevel@tonic-gate 			if (mmap((void *)laddr, size, PROT_NONE,
3197c478bd9Sstevel@tonic-gate 			    (MAP_FIXED | MAP_PRIVATE), fd, 0) == MAP_FAILED) {
3207c478bd9Sstevel@tonic-gate 				err = errno;
3217c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP),
3227c478bd9Sstevel@tonic-gate 				    MSG_ORIG(MSG_FIL_LIBCRLE),
3237c478bd9Sstevel@tonic-gate 				    MSG_ORIG(MSG_PTH_DEVNULL), strerror(err));
3247c478bd9Sstevel@tonic-gate 				return (1);
3257c478bd9Sstevel@tonic-gate 			}
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 		laddr = _maps->pr_vaddr + _maps->pr_size;
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * It's been observed that there may be space between the end of the
3327c478bd9Sstevel@tonic-gate 	 * last mapping (typically ld.so.1), and the kernel base address.  As
3337c478bd9Sstevel@tonic-gate 	 * there's no interface to determine the kernel base address, keep
3347c478bd9Sstevel@tonic-gate 	 * filling in pages until we get an error.  We'll get ENOMEM once we
3357c478bd9Sstevel@tonic-gate 	 * hit the kernel base address.
3367c478bd9Sstevel@tonic-gate 	 */
3377c478bd9Sstevel@tonic-gate 	while (laddr) {
3387c478bd9Sstevel@tonic-gate 		if (mmap((void *)laddr, syspagsz, PROT_NONE,
3397c478bd9Sstevel@tonic-gate 		    (MAP_FIXED | MAP_PRIVATE), fd, 0) == MAP_FAILED) {
3407c478bd9Sstevel@tonic-gate 			err = errno;
3417c478bd9Sstevel@tonic-gate 			if (err == ENOMEM)
3427c478bd9Sstevel@tonic-gate 				break;
3437c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP),
3447c478bd9Sstevel@tonic-gate 			    MSG_ORIG(MSG_FIL_LIBCRLE),
3457c478bd9Sstevel@tonic-gate 			    MSG_ORIG(MSG_PTH_DEVNULL), strerror(err));
3467c478bd9Sstevel@tonic-gate 			return (1);
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 		laddr += syspagsz;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * Close /dev/null.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	(void) close(fd);
3557c478bd9Sstevel@tonic-gate 	return (0);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate /*
3597c478bd9Sstevel@tonic-gate  * Dump alternative objects as part of building a configuration file.  A temp
3607c478bd9Sstevel@tonic-gate  * configuration is already built and made available to the process, and is
3617c478bd9Sstevel@tonic-gate  * located via dlinfo().  Having load()'ed each object, and dump()'ed its image,
3627c478bd9Sstevel@tonic-gate  * the final memory reservation infoamtion is returned to the caller.
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate int
dumpconfig(void)3657c478bd9Sstevel@tonic-gate dumpconfig(void)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	char		buffer[PATH_MAX];
3687c478bd9Sstevel@tonic-gate 	Addr		config;
3697c478bd9Sstevel@tonic-gate 	Dl_info		info;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/*
3727c478bd9Sstevel@tonic-gate 	 * Determine the configuration file and where it is mapped.
3737c478bd9Sstevel@tonic-gate 	 */
3747c478bd9Sstevel@tonic-gate 	if (dlinfo((void *)NULL, RTLD_DI_CONFIGADDR, &info) == -1) {
3757c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_DL_INFO),
3767c478bd9Sstevel@tonic-gate 		    MSG_ORIG(MSG_FIL_LIBCRLE), dlerror());
3777c478bd9Sstevel@tonic-gate 		return (1);
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 	config = (Addr)info.dli_fbase;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	/*
3827c478bd9Sstevel@tonic-gate 	 * Scan the configuration file for alternative entries.
3837c478bd9Sstevel@tonic-gate 	 */
3847c478bd9Sstevel@tonic-gate 	if (scanconfig(config, load) != 0)
3857c478bd9Sstevel@tonic-gate 		return (1);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	/*
3887c478bd9Sstevel@tonic-gate 	 * Having mapped all objects, relocate them.  It would be nice if we
3897c478bd9Sstevel@tonic-gate 	 * could drop this step altogether, and have dldump() carry out just
3907c478bd9Sstevel@tonic-gate 	 * those relocations required, but when binding to an application we
3917c478bd9Sstevel@tonic-gate 	 * need to handle copy relocations - these can affect bindings (in the
3927c478bd9Sstevel@tonic-gate 	 * case of things like libld.so which have direct bindings) and require
3937c478bd9Sstevel@tonic-gate 	 * that the data being copied is itself relocated.
3947c478bd9Sstevel@tonic-gate 	 */
3957c478bd9Sstevel@tonic-gate 	if (dlmopen(LM_ID_BASE, 0, (RTLD_NOW | RTLD_CONFGEN)) == 0)
3967c478bd9Sstevel@tonic-gate 		return (1);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	/*
3997c478bd9Sstevel@tonic-gate 	 * Rescan the configuration dumping out each alternative file.
4007c478bd9Sstevel@tonic-gate 	 */
4017c478bd9Sstevel@tonic-gate 	if (scanconfig(config, dump) != 0)
4027c478bd9Sstevel@tonic-gate 		return (1);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/*
4057c478bd9Sstevel@tonic-gate 	 * Having established the memory range of the dumped images and
4067c478bd9Sstevel@tonic-gate 	 * sucessfully dumped them out, report back to the caller.
4077c478bd9Sstevel@tonic-gate 	 */
4087c478bd9Sstevel@tonic-gate 	(void) sprintf(buffer, MSG_ORIG(MSG_AUD_RESBGN), EC_ADDR(membgn));
4097c478bd9Sstevel@tonic-gate 	(void) write(pfd, buffer, strlen(buffer));
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	(void) sprintf(buffer, MSG_ORIG(MSG_AUD_RESEND), EC_ADDR(memend));
4127c478bd9Sstevel@tonic-gate 	(void) write(pfd, buffer, strlen(buffer));
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	return (0);
4157c478bd9Sstevel@tonic-gate }
416