xref: /onnv-gate/usr/src/uts/common/krtld/kobj.c (revision 5331:3047ad28a67b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51544Seschrock  * Common Development and Distribution License (the "License").
61544Seschrock  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Kernel's linker/loader
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/param.h>
340Sstevel@tonic-gate #include <sys/sysmacros.h>
350Sstevel@tonic-gate #include <sys/systm.h>
360Sstevel@tonic-gate #include <sys/user.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
380Sstevel@tonic-gate #include <sys/reboot.h>
390Sstevel@tonic-gate #include <sys/bootconf.h>
400Sstevel@tonic-gate #include <sys/debug.h>
410Sstevel@tonic-gate #include <sys/uio.h>
420Sstevel@tonic-gate #include <sys/file.h>
430Sstevel@tonic-gate #include <sys/vnode.h>
440Sstevel@tonic-gate #include <sys/user.h>
450Sstevel@tonic-gate #include <sys/mman.h>
460Sstevel@tonic-gate #include <vm/as.h>
470Sstevel@tonic-gate #include <vm/seg_kp.h>
480Sstevel@tonic-gate #include <vm/seg_kmem.h>
490Sstevel@tonic-gate #include <sys/elf.h>
500Sstevel@tonic-gate #include <sys/elf_notes.h>
510Sstevel@tonic-gate #include <sys/vmsystm.h>
520Sstevel@tonic-gate #include <sys/kdi.h>
530Sstevel@tonic-gate #include <sys/atomic.h>
540Sstevel@tonic-gate #include <sys/kmdb.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #include <sys/link.h>
570Sstevel@tonic-gate #include <sys/kobj.h>
580Sstevel@tonic-gate #include <sys/ksyms.h>
590Sstevel@tonic-gate #include <sys/disp.h>
600Sstevel@tonic-gate #include <sys/modctl.h>
610Sstevel@tonic-gate #include <sys/varargs.h>
620Sstevel@tonic-gate #include <sys/kstat.h>
630Sstevel@tonic-gate #include <sys/kobj_impl.h>
640Sstevel@tonic-gate #include <sys/callb.h>
650Sstevel@tonic-gate #include <sys/cmn_err.h>
660Sstevel@tonic-gate #include <sys/tnf_probe.h>
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #include <reloc.h>
690Sstevel@tonic-gate #include <kobj_kdi.h>
700Sstevel@tonic-gate #include <sys/sha1.h>
710Sstevel@tonic-gate #include <sys/crypto/elfsign.h>
720Sstevel@tonic-gate 
730Sstevel@tonic-gate #if !defined(__sparc)
740Sstevel@tonic-gate #include <sys/bootvfs.h>
750Sstevel@tonic-gate #endif
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * do_symbols() error codes
790Sstevel@tonic-gate  */
800Sstevel@tonic-gate #define	DOSYM_UNDEF		-1	/* undefined symbol */
810Sstevel@tonic-gate #define	DOSYM_UNSAFE		-2	/* MT-unsafe driver symbol */
820Sstevel@tonic-gate 
833446Smrj static void synthetic_bootaux(char *, val_t *);
843446Smrj static struct module *load_exec(val_t *, char *);
850Sstevel@tonic-gate static void load_linker(val_t *);
863446Smrj static struct modctl *add_primary(const char *filename, int);
870Sstevel@tonic-gate static int bind_primary(val_t *, int);
880Sstevel@tonic-gate static int load_primary(struct module *, int);
890Sstevel@tonic-gate static int load_kmdb(val_t *);
900Sstevel@tonic-gate static int get_progbits(struct module *, struct _buf *);
910Sstevel@tonic-gate static int get_syms(struct module *, struct _buf *);
920Sstevel@tonic-gate static int get_ctf(struct module *, struct _buf *);
930Sstevel@tonic-gate static void get_signature(struct module *, struct _buf *);
940Sstevel@tonic-gate static int do_common(struct module *);
950Sstevel@tonic-gate static void add_dependent(struct module *, struct module *);
960Sstevel@tonic-gate static int do_dependents(struct modctl *, char *, size_t);
970Sstevel@tonic-gate static int do_symbols(struct module *, Elf64_Addr);
980Sstevel@tonic-gate static void module_assign(struct modctl *, struct module *);
990Sstevel@tonic-gate static void free_module_data(struct module *);
1000Sstevel@tonic-gate static char *depends_on(struct module *);
1013446Smrj static char *getmodpath(const char *);
1020Sstevel@tonic-gate static char *basename(char *);
1030Sstevel@tonic-gate static void attr_val(val_t *);
1040Sstevel@tonic-gate static char *find_libmacro(char *);
1050Sstevel@tonic-gate static char *expand_libmacro(char *, char *, char *);
1060Sstevel@tonic-gate static int read_bootflags(void);
1070Sstevel@tonic-gate static int kobj_boot_open(char *, int);
1080Sstevel@tonic-gate static int kobj_boot_close(int);
1090Sstevel@tonic-gate static int kobj_boot_seek(int, off_t, off_t);
1100Sstevel@tonic-gate static int kobj_boot_read(int, caddr_t, size_t);
1111544Seschrock static int kobj_boot_fstat(int, struct bootstat *);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate static Sym *lookup_one(struct module *, const char *);
1140Sstevel@tonic-gate static void sym_insert(struct module *, char *, symid_t);
1150Sstevel@tonic-gate static Sym *sym_lookup(struct module *, Sym *);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*PRINTFLIKE2*/
1180Sstevel@tonic-gate static void kprintf(void *, const char *, ...)  __KPRINTFLIKE(2);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static struct kobjopen_tctl *kobjopen_alloc(char *filename);
1210Sstevel@tonic-gate static void kobjopen_free(struct kobjopen_tctl *ltp);
1220Sstevel@tonic-gate static void kobjopen_thread(struct kobjopen_tctl *ltp);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate extern int kcopy(const void *, void *, size_t);
1250Sstevel@tonic-gate extern int elf_mach_ok(Ehdr *);
1260Sstevel@tonic-gate extern int alloc_gottable(struct module *, caddr_t *, caddr_t *);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate static void tnf_unsplice_probes(unsigned int, struct modctl *);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate extern int modrootloaded;
1310Sstevel@tonic-gate extern int swaploaded;
1320Sstevel@tonic-gate extern int bop_io_quiesced;
1330Sstevel@tonic-gate extern int last_module_id;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate #ifdef KOBJ_DEBUG
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * Values that can be or'd in to kobj_debug and their effects:
1380Sstevel@tonic-gate  *
1390Sstevel@tonic-gate  *	D_DEBUG		- misc. debugging information.
1400Sstevel@tonic-gate  *	D_SYMBOLS	- list symbols and their values as they are entered
1410Sstevel@tonic-gate  *			  into the hash table
1420Sstevel@tonic-gate  *	D_RELOCATIONS	- display relocation processing information
1430Sstevel@tonic-gate  *	D_LOADING	- display information about each module as it
1440Sstevel@tonic-gate  *			  is loaded.
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate int kobj_debug = 0;
1473446Smrj 
1483446Smrj #define	KOBJ_MARK(s)	if (kobj_debug & D_DEBUG)	\
1493446Smrj 	(_kobj_printf(ops, "%d", __LINE__), _kobj_printf(ops, ": %s\n", s))
1503446Smrj #else
1513446Smrj #define	KOBJ_MARK(s)	/* discard */
1520Sstevel@tonic-gate #endif
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate #define	MODPATH_PROPNAME	"module-path"
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
1570Sstevel@tonic-gate static char slash_moddir_suffix_slash[] = MODDIR_SUFFIX "/";
1580Sstevel@tonic-gate #else
1590Sstevel@tonic-gate #define	slash_moddir_suffix_slash	""
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate #define	_moddebug	get_weakish_int(&moddebug)
1630Sstevel@tonic-gate #define	_modrootloaded	get_weakish_int(&modrootloaded)
1640Sstevel@tonic-gate #define	_swaploaded	get_weakish_int(&swaploaded)
1650Sstevel@tonic-gate #define	_ioquiesced	get_weakish_int(&bop_io_quiesced)
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate #define	mod(X)		(struct module *)((X)->modl_modp->mod_mp)
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate void	*romp;		/* rom vector (opaque to us) */
1700Sstevel@tonic-gate struct bootops *ops;	/* bootops vector */
1710Sstevel@tonic-gate void *dbvec;		/* debug vector */
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /*
1740Sstevel@tonic-gate  * kobjopen thread control structure
1750Sstevel@tonic-gate  */
1760Sstevel@tonic-gate struct kobjopen_tctl {
1770Sstevel@tonic-gate 	ksema_t		sema;
1780Sstevel@tonic-gate 	char		*name;		/* name of file */
1790Sstevel@tonic-gate 	struct vnode	*vp;		/* vnode return from vn_open() */
1800Sstevel@tonic-gate 	int		Errno;		/* error return from vnopen    */
1810Sstevel@tonic-gate };
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate  * Structure for defining dynamically expandable library macros
1850Sstevel@tonic-gate  */
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate struct lib_macro_info {
1880Sstevel@tonic-gate 	char	*lmi_list;		/* ptr to list of possible choices */
1890Sstevel@tonic-gate 	char	*lmi_macroname;		/* pointer to macro name */
1900Sstevel@tonic-gate 	ushort_t lmi_ba_index;		/* index into bootaux vector */
1910Sstevel@tonic-gate 	ushort_t lmi_macrolen;		/* macro length */
1920Sstevel@tonic-gate } libmacros[] = {
1930Sstevel@tonic-gate 	{ NULL, "CPU", BA_CPU, 0 },
1940Sstevel@tonic-gate 	{ NULL, "MMU", BA_MMU, 0 }
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate #define	NLIBMACROS	sizeof (libmacros) / sizeof (struct lib_macro_info)
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate char *boot_cpu_compatible_list;			/* make $CPU available */
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate #ifdef	MPSAS
2020Sstevel@tonic-gate void	sas_prisyms(struct modctl_list *);
2030Sstevel@tonic-gate void	sas_syms(struct module *);
2040Sstevel@tonic-gate #endif
2050Sstevel@tonic-gate 
2063446Smrj char *kobj_module_path;				/* module search path */
2070Sstevel@tonic-gate vmem_t	*text_arena;				/* module text arena */
2080Sstevel@tonic-gate static vmem_t *data_arena;			/* module data & bss arena */
2090Sstevel@tonic-gate static vmem_t *ctf_arena;			/* CTF debug data arena */
2100Sstevel@tonic-gate static struct modctl *kobj_modules = NULL;	/* modules loaded */
2110Sstevel@tonic-gate int kobj_mmu_pagesize;				/* system pagesize */
2120Sstevel@tonic-gate static int lg_pagesize;				/* "large" pagesize */
2130Sstevel@tonic-gate static int kobj_last_module_id = 0;		/* id assignment */
2140Sstevel@tonic-gate static kmutex_t kobj_lock;			/* protects mach memory list */
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  * The following functions have been implemented by the kernel.
2180Sstevel@tonic-gate  * However, many 3rd party drivers provide their own implementations
2190Sstevel@tonic-gate  * of these functions.  When such drivers are loaded, messages
220*5331Samw  * indicating that these symbols have been multiply defined will be
2210Sstevel@tonic-gate  * emitted to the console.  To avoid alarming customers for no good
2220Sstevel@tonic-gate  * reason, we simply suppress such warnings for the following set of
2230Sstevel@tonic-gate  * functions.
2240Sstevel@tonic-gate  */
2250Sstevel@tonic-gate static char *suppress_sym_list[] =
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate 	"strstr",
2280Sstevel@tonic-gate 	"strncat",
2290Sstevel@tonic-gate 	"strlcat",
2300Sstevel@tonic-gate 	"strlcpy",
2310Sstevel@tonic-gate 	"strspn",
2320Sstevel@tonic-gate 	"memcpy",
2330Sstevel@tonic-gate 	"memset",
2340Sstevel@tonic-gate 	"memmove",
2350Sstevel@tonic-gate 	"memcmp",
2360Sstevel@tonic-gate 	"memchr",
2370Sstevel@tonic-gate 	"__udivdi3",
2380Sstevel@tonic-gate 	"__divdi3",
2390Sstevel@tonic-gate 	"__umoddi3",
2400Sstevel@tonic-gate 	"__moddi3",
2410Sstevel@tonic-gate 	NULL		/* This entry must exist */
2420Sstevel@tonic-gate };
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /* indexed by KOBJ_NOTIFY_* */
2450Sstevel@tonic-gate static kobj_notify_list_t *kobj_notifiers[KOBJ_NOTIFY_MAX + 1];
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate /*
2480Sstevel@tonic-gate  * TNF probe management globals
2490Sstevel@tonic-gate  */
2500Sstevel@tonic-gate tnf_probe_control_t	*__tnf_probe_list_head = NULL;
2510Sstevel@tonic-gate tnf_tag_data_t		*__tnf_tag_list_head = NULL;
2520Sstevel@tonic-gate int			tnf_changed_probe_list = 0;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * Prefix for statically defined tracing (SDT) DTrace probes.
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate const char		*sdt_prefix = "__dtrace_probe_";
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate #if defined(__sparc)
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate  * Some PROMs return SUNW,UltraSPARC when they actually have
2620Sstevel@tonic-gate  * SUNW,UltraSPARC-II cpus. SInce we're now filtering out all
2630Sstevel@tonic-gate  * SUNW,UltraSPARC systems during the boot phase, we can safely
2640Sstevel@tonic-gate  * point the auxv CPU value at SUNW,UltraSPARC-II. This is what
2650Sstevel@tonic-gate  * we point it at.
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate const char		*ultra_2 = "SUNW,UltraSPARC-II";
2680Sstevel@tonic-gate #endif
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate /*
2713446Smrj  * Beginning and end of the kernel's dynamic text/data segments.
2720Sstevel@tonic-gate  */
2730Sstevel@tonic-gate static caddr_t _text;
2740Sstevel@tonic-gate static caddr_t _etext;
2753446Smrj static caddr_t _data;
2763446Smrj 
2773446Smrj /*
2783446Smrj  * XXX Hmm. The sparc linker fails to define this symbol.
2793446Smrj  */
2803446Smrj #if !defined(__sparc)
2813446Smrj extern
2823446Smrj #endif
2830Sstevel@tonic-gate caddr_t _edata;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate static Addr dynseg = 0;	/* load address of "dynamic" segment */
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate int standalone = 1;			/* an unwholey kernel? */
2880Sstevel@tonic-gate int use_iflush;				/* iflush after relocations */
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * _kobj_printf()
2920Sstevel@tonic-gate  *
2930Sstevel@tonic-gate  * Common printf function pointer. Can handle only one conversion
2940Sstevel@tonic-gate  * specification in the format string. Some of the functions invoked
2950Sstevel@tonic-gate  * through this function pointer cannot handle more that one conversion
2960Sstevel@tonic-gate  * specification in the format string.
2970Sstevel@tonic-gate  */
2980Sstevel@tonic-gate void (*_kobj_printf)(void *, const char *, ...);	/* printf routine */
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate static kobj_stat_t kobj_stat;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate #define	MINALIGN	8	/* at least a double-word */
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate int
3050Sstevel@tonic-gate get_weakish_int(int *ip)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	if (standalone)
3080Sstevel@tonic-gate 		return (0);
3090Sstevel@tonic-gate 	return (ip == NULL ? 0 : *ip);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate static void *
3130Sstevel@tonic-gate get_weakish_pointer(void **ptrp)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	if (standalone)
3160Sstevel@tonic-gate 		return (0);
3170Sstevel@tonic-gate 	return (ptrp == NULL ? 0 : *ptrp);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate /*
3210Sstevel@tonic-gate  * XXX fix dependencies on "kernel"; this should work
3220Sstevel@tonic-gate  * for other standalone binaries as well.
3230Sstevel@tonic-gate  *
3240Sstevel@tonic-gate  * XXX Fix hashing code to use one pointer to
3250Sstevel@tonic-gate  * hash entries.
3260Sstevel@tonic-gate  *	|----------|
3270Sstevel@tonic-gate  *	| nbuckets |
3280Sstevel@tonic-gate  *	|----------|
3290Sstevel@tonic-gate  *	| nchains  |
3300Sstevel@tonic-gate  *	|----------|
3310Sstevel@tonic-gate  *	| bucket[] |
3320Sstevel@tonic-gate  *	|----------|
3330Sstevel@tonic-gate  *	| chain[]  |
3340Sstevel@tonic-gate  *	|----------|
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate /*
3380Sstevel@tonic-gate  * Load, bind and relocate all modules that
3390Sstevel@tonic-gate  * form the primary kernel. At this point, our
3400Sstevel@tonic-gate  * externals have not been relocated.
3410Sstevel@tonic-gate  */
3420Sstevel@tonic-gate void
3430Sstevel@tonic-gate kobj_init(
3440Sstevel@tonic-gate 	void *romvec,
3450Sstevel@tonic-gate 	void *dvec,
3460Sstevel@tonic-gate 	struct bootops *bootvec,
3470Sstevel@tonic-gate 	val_t *bootaux)
3480Sstevel@tonic-gate {
3490Sstevel@tonic-gate 	struct module *mp;
3500Sstevel@tonic-gate 	struct modctl *modp;
3510Sstevel@tonic-gate 	Addr entry;
3523446Smrj 	char filename[MAXPATHLEN];
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * Save these to pass on to
3560Sstevel@tonic-gate 	 * the booted standalone.
3570Sstevel@tonic-gate 	 */
3580Sstevel@tonic-gate 	romp = romvec;
3590Sstevel@tonic-gate 	dbvec = dvec;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	ops = bootvec;
3620Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
3630Sstevel@tonic-gate 	_kobj_printf = (void (*)(void *, const char *, ...))ops->bsys_printf;
3640Sstevel@tonic-gate #else
3650Sstevel@tonic-gate 	_kobj_printf = (void (*)(void *, const char *, ...))bop_putsarg;
3660Sstevel@tonic-gate #endif
3673446Smrj 	KOBJ_MARK("Entered kobj_init()");
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate #if defined(__sparc)
3700Sstevel@tonic-gate 	/* XXXQ should suppress this test on sun4v */
3710Sstevel@tonic-gate 	if (bootaux[BA_CPU].ba_ptr) {
3720Sstevel@tonic-gate 		if (strcmp("SUNW,UltraSPARC", bootaux[BA_CPU].ba_ptr) == 0) {
3730Sstevel@tonic-gate 			bootaux[BA_CPU].ba_ptr = (void *) ultra_2;
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate #endif
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * Check bootops version.
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 	if (BOP_GETVERSION(ops) != BO_VERSION) {
3820Sstevel@tonic-gate 		_kobj_printf(ops, "Warning: Using boot version %d, ",
3830Sstevel@tonic-gate 		    BOP_GETVERSION(ops));
3840Sstevel@tonic-gate 		_kobj_printf(ops, "expected %d\n", BO_VERSION);
3850Sstevel@tonic-gate 	}
3863446Smrj #ifdef KOBJ_DEBUG
3873446Smrj 	else if (kobj_debug & D_DEBUG) {
3883446Smrj 		/*
3893446Smrj 		 * Say -something- so we know we got this far ..
3903446Smrj 		 */
3913446Smrj 		_kobj_printf(ops, "krtld: Using boot version %d.\n",
3923446Smrj 		    BOP_GETVERSION(ops));
3933446Smrj 	}
3943446Smrj #endif
3953446Smrj 
3963446Smrj 	(void) BOP_GETPROP(ops, "whoami", filename);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * We don't support standalone debuggers anymore.  The use of kadb
4000Sstevel@tonic-gate 	 * will interfere with the later use of kmdb.  Let the user mend
4010Sstevel@tonic-gate 	 * their ways now.  Users will reach this message if they still
4020Sstevel@tonic-gate 	 * have the kadb binary on their system (perhaps they used an old
4030Sstevel@tonic-gate 	 * bfu, or maybe they intentionally copied it there) and have
4040Sstevel@tonic-gate 	 * specified its use in a way that eluded our checking in the boot
4050Sstevel@tonic-gate 	 * program.
4060Sstevel@tonic-gate 	 */
4070Sstevel@tonic-gate 	if (dvec != NULL) {
4080Sstevel@tonic-gate 		_kobj_printf(ops, "\nWARNING: Standalone debuggers such as "
4090Sstevel@tonic-gate 		    "kadb are no longer supported\n\n");
4100Sstevel@tonic-gate 		goto fail;
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate #ifndef __sparc
4140Sstevel@tonic-gate 	{
4150Sstevel@tonic-gate 		/* on x86, we always boot with a ramdisk */
4160Sstevel@tonic-gate 		extern int kobj_boot_mountroot(void);
4170Sstevel@tonic-gate 		(void) kobj_boot_mountroot();
4183446Smrj 
4193446Smrj 		/*
4203446Smrj 		 * Now that the ramdisk is mounted, finish boot property
4213446Smrj 		 * initialization.
4223446Smrj 		 */
4233446Smrj 		boot_prop_finish();
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate #endif
4260Sstevel@tonic-gate 
4273446Smrj #if !defined(_UNIX_KRTLD)
4283446Smrj 	/*
4293446Smrj 	 * If 'unix' is linked together with 'krtld' into one executable,
4303446Smrj 	 * the early boot code does -not- hand us any of the dynamic metadata
4313446Smrj 	 * about the executable. In particular, it does not read in, map or
4323446Smrj 	 * otherwise look at the program headers. We fake all that up now.
4333446Smrj 	 *
4343446Smrj 	 * We do this early as DTrace static probes and tnf probes both call
4353446Smrj 	 * undefined references.  We have to process those relocations before
4363446Smrj 	 * calling any of them.
4373446Smrj 	 */
4383446Smrj 	if (bootaux[BA_PHDR].ba_ptr == NULL)
4393446Smrj 		synthetic_bootaux(filename, bootaux);
4403446Smrj #endif
4413446Smrj 
4423446Smrj 	/*
4433446Smrj 	 * Save the interesting attribute-values
4443446Smrj 	 * (scanned by kobj_boot).
4453446Smrj 	 */
4463446Smrj 	attr_val(bootaux);
4473446Smrj 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * Set the module search path.
4500Sstevel@tonic-gate 	 */
4513446Smrj 	kobj_module_path = getmodpath(filename);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	boot_cpu_compatible_list = find_libmacro("CPU");
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/*
4560Sstevel@tonic-gate 	 * These two modules have actually been
4570Sstevel@tonic-gate 	 * loaded by boot, but we finish the job
4580Sstevel@tonic-gate 	 * by introducing them into the world of
4590Sstevel@tonic-gate 	 * loadable modules.
4600Sstevel@tonic-gate 	 */
4610Sstevel@tonic-gate 
4623446Smrj 	mp = load_exec(bootaux, filename);
4630Sstevel@tonic-gate 	load_linker(bootaux);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	/*
4660Sstevel@tonic-gate 	 * Load all the primary dependent modules.
4670Sstevel@tonic-gate 	 */
4680Sstevel@tonic-gate 	if (load_primary(mp, KOBJ_LM_PRIMARY) == -1)
4690Sstevel@tonic-gate 		goto fail;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	/*
4720Sstevel@tonic-gate 	 * Glue it together.
4730Sstevel@tonic-gate 	 */
4740Sstevel@tonic-gate 	if (bind_primary(bootaux, KOBJ_LM_PRIMARY) == -1)
4750Sstevel@tonic-gate 		goto fail;
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	entry = bootaux[BA_ENTRY].ba_val;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate #ifdef	__sparc
4800Sstevel@tonic-gate 	/*
4810Sstevel@tonic-gate 	 * On sparcv9, boot scratch memory is running out.
4820Sstevel@tonic-gate 	 * Free the temporary allocations here to allow boot
4830Sstevel@tonic-gate 	 * to continue.
4840Sstevel@tonic-gate 	 */
4850Sstevel@tonic-gate 	kobj_tmp_free();
4860Sstevel@tonic-gate #endif
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/*
4890Sstevel@tonic-gate 	 * Get the boot flags
4900Sstevel@tonic-gate 	 */
4910Sstevel@tonic-gate 	bootflags(ops);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	if (boothowto & RB_VERBOSE)
4940Sstevel@tonic-gate 		kobj_lm_dump(KOBJ_LM_PRIMARY);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	kobj_kdi_init();
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	if (boothowto & RB_KMDB) {
4990Sstevel@tonic-gate 		if (load_kmdb(bootaux) < 0)
5000Sstevel@tonic-gate 			goto fail;
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	/*
5040Sstevel@tonic-gate 	 * Post setup.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate #ifdef	MPSAS
5070Sstevel@tonic-gate 	sas_prisyms(kobj_lm_lookup(KOBJ_LM_PRIMARY));
5080Sstevel@tonic-gate #endif
5090Sstevel@tonic-gate 	s_text = _text;
5100Sstevel@tonic-gate 	e_text = _etext;
5110Sstevel@tonic-gate 	s_data = _data;
5120Sstevel@tonic-gate 	e_data = _edata;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	kobj_sync_instruction_memory(s_text, e_text - s_text);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
5170Sstevel@tonic-gate 	if (kobj_debug & D_DEBUG)
5180Sstevel@tonic-gate 		_kobj_printf(ops,
5190Sstevel@tonic-gate 		    "krtld: transferring control to: 0x%p\n", entry);
5200Sstevel@tonic-gate #endif
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	/*
5230Sstevel@tonic-gate 	 * Make sure the mod system knows about the modules already loaded.
5240Sstevel@tonic-gate 	 */
5250Sstevel@tonic-gate 	last_module_id = kobj_last_module_id;
5260Sstevel@tonic-gate 	bcopy(kobj_modules, &modules, sizeof (modules));
5270Sstevel@tonic-gate 	modp = &modules;
5280Sstevel@tonic-gate 	do {
5290Sstevel@tonic-gate 		if (modp->mod_next == kobj_modules)
5300Sstevel@tonic-gate 			modp->mod_next = &modules;
5310Sstevel@tonic-gate 		if (modp->mod_prev == kobj_modules)
5320Sstevel@tonic-gate 			modp->mod_prev = &modules;
5330Sstevel@tonic-gate 	} while ((modp = modp->mod_next) != &modules);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	standalone = 0;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate #ifdef	__sparc
5380Sstevel@tonic-gate 	/*
5390Sstevel@tonic-gate 	 * On sparcv9, boot scratch memory is running out.
5400Sstevel@tonic-gate 	 * Free the temporary allocations here to allow boot
5410Sstevel@tonic-gate 	 * to continue.
5420Sstevel@tonic-gate 	 */
5430Sstevel@tonic-gate 	kobj_tmp_free();
5440Sstevel@tonic-gate #endif
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	_kobj_printf = kprintf;
5470Sstevel@tonic-gate 	exitto((caddr_t)entry);
5480Sstevel@tonic-gate fail:
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	_kobj_printf(ops, "krtld: error during initial load/link phase\n");
5514159Sjosephb 
5524159Sjosephb #if !defined(_UNIX_KRTLD)
5534159Sjosephb 	_kobj_printf(ops, "\n");
5544159Sjosephb 	_kobj_printf(ops, "krtld could neither locate nor resolve symbols"
5554159Sjosephb 	    " for:\n");
5564159Sjosephb 	_kobj_printf(ops, "    %s\n", filename);
5574159Sjosephb 	_kobj_printf(ops, "in the boot archive. Please verify that this"
5584159Sjosephb 	    " file\n");
5594159Sjosephb 	_kobj_printf(ops, "matches what is found in the boot archive.\n");
5604159Sjosephb 	_kobj_printf(ops, "You may need to boot using the Solaris failsafe to"
5614159Sjosephb 	    " fix this.\n");
5624159Sjosephb 	bop_panic("Unable to boot");
5634159Sjosephb #endif
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate 
5663446Smrj #if !defined(_UNIX_KRTLD)
5673446Smrj /*
5683446Smrj  * Synthesize additional metadata that describes the executable.
5693446Smrj  *
5703446Smrj  * (When the dynamic executable has an interpreter, the boot program
5713446Smrj  * does all this for us.  Where we don't have an interpreter, (or a
5723446Smrj  * even a boot program, perhaps) we have to do this for ourselves.)
5733446Smrj  */
5743446Smrj static void
5753446Smrj synthetic_bootaux(char *filename, val_t *bootaux)
5763446Smrj {
5773446Smrj 	Ehdr ehdr;
5783446Smrj 	caddr_t phdrbase;
5793446Smrj 	struct _buf *file;
5803446Smrj 	int i, n;
5813446Smrj 
5823446Smrj 	/*
5833446Smrj 	 * Elf header
5843446Smrj 	 */
5853446Smrj 	KOBJ_MARK("synthetic_bootaux()");
5863446Smrj 	KOBJ_MARK(filename);
5873446Smrj 	file = kobj_open_file(filename);
5883446Smrj 	if (file == (struct _buf *)-1) {
5893446Smrj 		_kobj_printf(ops, "krtld: failed to open '%s'\n", filename);
5903446Smrj 		return;
5913446Smrj 	}
5923446Smrj 	KOBJ_MARK("reading program headers");
5933446Smrj 	if (kobj_read_file(file, (char *)&ehdr, sizeof (ehdr), 0) < 0) {
5943446Smrj 		_kobj_printf(ops, "krtld: %s: failed to read ehder\n",
5953446Smrj 		    filename);
5963446Smrj 		return;
5973446Smrj 	}
5983446Smrj 
5993446Smrj 	/*
6003446Smrj 	 * Program headers
6013446Smrj 	 */
6023446Smrj 	bootaux[BA_PHNUM].ba_val = ehdr.e_phnum;
6033446Smrj 	bootaux[BA_PHENT].ba_val = ehdr.e_phentsize;
6043446Smrj 	n = ehdr.e_phentsize * ehdr.e_phnum;
6053446Smrj 
6063446Smrj 	phdrbase = kobj_alloc(n, KM_WAIT | KM_TMP);
6073446Smrj 
6083446Smrj 	if (kobj_read_file(file, phdrbase, n, ehdr.e_phoff) < 0) {
6093446Smrj 		_kobj_printf(ops, "krtld: %s: failed to read phdrs\n",
6103446Smrj 		    filename);
6113446Smrj 		return;
6123446Smrj 	}
6133446Smrj 	bootaux[BA_PHDR].ba_ptr = phdrbase;
6143446Smrj 	kobj_close_file(file);
6153446Smrj 	KOBJ_MARK("closed file");
6163446Smrj 
6173446Smrj 	/*
6183446Smrj 	 * Find the dynamic section address
6193446Smrj 	 */
6203446Smrj 	for (i = 0; i < ehdr.e_phnum; i++) {
6213446Smrj 		Phdr *phdr = (Phdr *)(phdrbase + ehdr.e_phentsize * i);
6223446Smrj 
6233446Smrj 		if (phdr->p_type == PT_DYNAMIC) {
6243446Smrj 			bootaux[BA_DYNAMIC].ba_ptr = (void *)phdr->p_vaddr;
6253446Smrj 			break;
6263446Smrj 		}
6273446Smrj 	}
6283446Smrj 	KOBJ_MARK("synthetic_bootaux() done");
6293446Smrj }
6303446Smrj #endif
6313446Smrj 
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate  * Set up any global information derived
6340Sstevel@tonic-gate  * from attribute/values in the boot or
6350Sstevel@tonic-gate  * aux vector.
6360Sstevel@tonic-gate  */
6370Sstevel@tonic-gate static void
6380Sstevel@tonic-gate attr_val(val_t *bootaux)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	Phdr *phdr;
6410Sstevel@tonic-gate 	int phnum, phsize;
6420Sstevel@tonic-gate 	int i;
6430Sstevel@tonic-gate 
6443446Smrj 	KOBJ_MARK("attr_val()");
6450Sstevel@tonic-gate 	kobj_mmu_pagesize = bootaux[BA_PAGESZ].ba_val;
6460Sstevel@tonic-gate 	lg_pagesize = bootaux[BA_LPAGESZ].ba_val;
6470Sstevel@tonic-gate 	use_iflush = bootaux[BA_IFLUSH].ba_val;
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	phdr = (Phdr *)bootaux[BA_PHDR].ba_ptr;
6500Sstevel@tonic-gate 	phnum = bootaux[BA_PHNUM].ba_val;
6510Sstevel@tonic-gate 	phsize = bootaux[BA_PHENT].ba_val;
6520Sstevel@tonic-gate 	for (i = 0; i < phnum; i++) {
6530Sstevel@tonic-gate 		phdr = (Phdr *)(bootaux[BA_PHDR].ba_val + i * phsize);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		if (phdr->p_type != PT_LOAD)
6560Sstevel@tonic-gate 			continue;
6570Sstevel@tonic-gate 		/*
6580Sstevel@tonic-gate 		 * Bounds of the various segments.
6590Sstevel@tonic-gate 		 */
6600Sstevel@tonic-gate 		if (!(phdr->p_flags & PF_X)) {
6613446Smrj #if defined(_UNIX_KRTLD)
6620Sstevel@tonic-gate 			dynseg = phdr->p_vaddr;
6633446Smrj #else
6643446Smrj 			ASSERT(phdr->p_vaddr == 0);
6653446Smrj #endif
6660Sstevel@tonic-gate 		} else {
6670Sstevel@tonic-gate 			if (phdr->p_flags & PF_W) {
6683446Smrj 				_data = (caddr_t)phdr->p_vaddr;
6693446Smrj 				_edata = _data + phdr->p_memsz;
6700Sstevel@tonic-gate 			} else {
6710Sstevel@tonic-gate 				_text = (caddr_t)phdr->p_vaddr;
6720Sstevel@tonic-gate 				_etext = _text + phdr->p_memsz;
6730Sstevel@tonic-gate 			}
6740Sstevel@tonic-gate 		}
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/* To do the kobj_alloc, _edata needs to be set. */
6780Sstevel@tonic-gate 	for (i = 0; i < NLIBMACROS; i++) {
6790Sstevel@tonic-gate 		if (bootaux[libmacros[i].lmi_ba_index].ba_ptr != NULL) {
6800Sstevel@tonic-gate 			libmacros[i].lmi_list = kobj_alloc(
6810Sstevel@tonic-gate 			    strlen(bootaux[libmacros[i].lmi_ba_index].ba_ptr) +
6820Sstevel@tonic-gate 			    1, KM_WAIT);
6830Sstevel@tonic-gate 			(void) strcpy(libmacros[i].lmi_list,
6843912Slling 			    bootaux[libmacros[i].lmi_ba_index].ba_ptr);
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 		libmacros[i].lmi_macrolen = strlen(libmacros[i].lmi_macroname);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate  * Set up the booted executable.
6920Sstevel@tonic-gate  */
6930Sstevel@tonic-gate static struct module *
6943446Smrj load_exec(val_t *bootaux, char *filename)
6950Sstevel@tonic-gate {
6960Sstevel@tonic-gate 	struct modctl *cp;
6970Sstevel@tonic-gate 	struct module *mp;
6980Sstevel@tonic-gate 	Dyn *dyn;
6990Sstevel@tonic-gate 	Sym *sp;
7000Sstevel@tonic-gate 	int i, lsize, osize, nsize, allocsize;
7010Sstevel@tonic-gate 	char *libname, *tmp;
7020Sstevel@tonic-gate 
7033446Smrj 	/*
7043446Smrj 	 * Set the module search path.
7053446Smrj 	 */
7063446Smrj 	kobj_module_path = getmodpath(filename);
7073446Smrj 
7083446Smrj #ifdef KOBJ_DEBUG
7093446Smrj 	if (kobj_debug & D_DEBUG)
7103446Smrj 		_kobj_printf(ops, "module path '%s'\n", kobj_module_path);
7113446Smrj #endif
7123446Smrj 
7133446Smrj 	KOBJ_MARK("add_primary");
7140Sstevel@tonic-gate 	cp = add_primary(filename, KOBJ_LM_PRIMARY);
7150Sstevel@tonic-gate 
7163446Smrj 	KOBJ_MARK("struct module");
7170Sstevel@tonic-gate 	mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
7180Sstevel@tonic-gate 	cp->mod_mp = mp;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	/*
7210Sstevel@tonic-gate 	 * We don't have the following information
7220Sstevel@tonic-gate 	 * since this module is an executable and not
7230Sstevel@tonic-gate 	 * a relocatable .o.
7240Sstevel@tonic-gate 	 */
7250Sstevel@tonic-gate 	mp->symtbl_section = 0;
7260Sstevel@tonic-gate 	mp->shdrs = NULL;
7270Sstevel@tonic-gate 	mp->strhdr = NULL;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * Since this module is the only exception,
7310Sstevel@tonic-gate 	 * we cons up some section headers.
7320Sstevel@tonic-gate 	 */
7333446Smrj 	KOBJ_MARK("symhdr");
7340Sstevel@tonic-gate 	mp->symhdr = kobj_zalloc(sizeof (Shdr), KM_WAIT);
7353446Smrj 
7363446Smrj 	KOBJ_MARK("strhdr");
7370Sstevel@tonic-gate 	mp->strhdr = kobj_zalloc(sizeof (Shdr), KM_WAIT);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	mp->symhdr->sh_type = SHT_SYMTAB;
7400Sstevel@tonic-gate 	mp->strhdr->sh_type = SHT_STRTAB;
7410Sstevel@tonic-gate 	/*
7420Sstevel@tonic-gate 	 * Scan the dynamic structure.
7430Sstevel@tonic-gate 	 */
7440Sstevel@tonic-gate 	for (dyn = (Dyn *) bootaux[BA_DYNAMIC].ba_ptr;
7450Sstevel@tonic-gate 	    dyn->d_tag != DT_NULL; dyn++) {
7460Sstevel@tonic-gate 		switch (dyn->d_tag) {
7470Sstevel@tonic-gate 		case DT_SYMTAB:
7480Sstevel@tonic-gate 			dyn->d_un.d_ptr += dynseg;
7490Sstevel@tonic-gate 			mp->symspace = mp->symtbl = (char *)dyn->d_un.d_ptr;
7500Sstevel@tonic-gate 			mp->symhdr->sh_addr = dyn->d_un.d_ptr;
7510Sstevel@tonic-gate 			break;
7520Sstevel@tonic-gate 		case DT_HASH:
7530Sstevel@tonic-gate 			dyn->d_un.d_ptr += dynseg;
7540Sstevel@tonic-gate 			mp->nsyms = *((uint_t *)dyn->d_un.d_ptr + 1);
7550Sstevel@tonic-gate 			mp->hashsize = *(uint_t *)dyn->d_un.d_ptr;
7560Sstevel@tonic-gate 			break;
7570Sstevel@tonic-gate 		case DT_STRTAB:
7580Sstevel@tonic-gate 			dyn->d_un.d_ptr += dynseg;
7590Sstevel@tonic-gate 			mp->strings = (char *)dyn->d_un.d_ptr;
7600Sstevel@tonic-gate 			mp->strhdr->sh_addr = dyn->d_un.d_ptr;
7610Sstevel@tonic-gate 			break;
7620Sstevel@tonic-gate 		case DT_STRSZ:
7630Sstevel@tonic-gate 			mp->strhdr->sh_size = dyn->d_un.d_val;
7640Sstevel@tonic-gate 			break;
7650Sstevel@tonic-gate 		case DT_SYMENT:
7660Sstevel@tonic-gate 			mp->symhdr->sh_entsize = dyn->d_un.d_val;
7670Sstevel@tonic-gate 			break;
7680Sstevel@tonic-gate 		}
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/*
7720Sstevel@tonic-gate 	 * Collapse any DT_NEEDED entries into one string.
7730Sstevel@tonic-gate 	 */
7740Sstevel@tonic-gate 	nsize = osize = 0;
7750Sstevel@tonic-gate 	allocsize = MAXPATHLEN;
7760Sstevel@tonic-gate 
7773446Smrj 	KOBJ_MARK("depends_on");
7780Sstevel@tonic-gate 	mp->depends_on = kobj_alloc(allocsize, KM_WAIT);
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	for (dyn = (Dyn *) bootaux[BA_DYNAMIC].ba_ptr;
7810Sstevel@tonic-gate 	    dyn->d_tag != DT_NULL; dyn++)
7820Sstevel@tonic-gate 		if (dyn->d_tag == DT_NEEDED) {
7830Sstevel@tonic-gate 			char *_lib;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 			libname = mp->strings + dyn->d_un.d_val;
7860Sstevel@tonic-gate 			if (strchr(libname, '$') != NULL) {
7870Sstevel@tonic-gate 				if ((_lib = expand_libmacro(libname,
7880Sstevel@tonic-gate 				    filename, filename)) != NULL)
7890Sstevel@tonic-gate 					libname = _lib;
7900Sstevel@tonic-gate 				else
7910Sstevel@tonic-gate 					_kobj_printf(ops, "krtld: "
7920Sstevel@tonic-gate 					    "load_exec: fail to "
7930Sstevel@tonic-gate 					    "expand %s\n", libname);
7940Sstevel@tonic-gate 			}
7950Sstevel@tonic-gate 			lsize = strlen(libname);
7960Sstevel@tonic-gate 			nsize += lsize;
7970Sstevel@tonic-gate 			if (nsize + 1 > allocsize) {
7983446Smrj 				KOBJ_MARK("grow depends_on");
7990Sstevel@tonic-gate 				tmp = kobj_alloc(allocsize + MAXPATHLEN,
8000Sstevel@tonic-gate 				    KM_WAIT);
8010Sstevel@tonic-gate 				bcopy(mp->depends_on, tmp, osize);
8020Sstevel@tonic-gate 				kobj_free(mp->depends_on, allocsize);
8030Sstevel@tonic-gate 				mp->depends_on = tmp;
8040Sstevel@tonic-gate 				allocsize += MAXPATHLEN;
8050Sstevel@tonic-gate 			}
8060Sstevel@tonic-gate 			bcopy(libname, mp->depends_on + osize, lsize);
807*5331Samw 			*(mp->depends_on + nsize) = ' '; /* separate */
8080Sstevel@tonic-gate 			nsize++;
8090Sstevel@tonic-gate 			osize = nsize;
8100Sstevel@tonic-gate 		}
8110Sstevel@tonic-gate 	if (nsize) {
8120Sstevel@tonic-gate 		mp->depends_on[nsize - 1] = '\0'; /* terminate the string */
8130Sstevel@tonic-gate 		/*
8140Sstevel@tonic-gate 		 * alloc with exact size and copy whatever it got over
8150Sstevel@tonic-gate 		 */
8163446Smrj 		KOBJ_MARK("realloc depends_on");
8170Sstevel@tonic-gate 		tmp = kobj_alloc(nsize, KM_WAIT);
8180Sstevel@tonic-gate 		bcopy(mp->depends_on, tmp, nsize);
8190Sstevel@tonic-gate 		kobj_free(mp->depends_on, allocsize);
8200Sstevel@tonic-gate 		mp->depends_on = tmp;
8210Sstevel@tonic-gate 	} else {
8220Sstevel@tonic-gate 		kobj_free(mp->depends_on, allocsize);
8230Sstevel@tonic-gate 		mp->depends_on = NULL;
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	mp->flags = KOBJ_EXEC|KOBJ_PRIM;	/* NOT a relocatable .o */
8270Sstevel@tonic-gate 	mp->symhdr->sh_size = mp->nsyms * mp->symhdr->sh_entsize;
8280Sstevel@tonic-gate 	/*
8290Sstevel@tonic-gate 	 * We allocate our own table since we don't
8300Sstevel@tonic-gate 	 * hash undefined references.
8310Sstevel@tonic-gate 	 */
8323446Smrj 	KOBJ_MARK("chains");
8330Sstevel@tonic-gate 	mp->chains = kobj_zalloc(mp->nsyms * sizeof (symid_t), KM_WAIT);
8343446Smrj 	KOBJ_MARK("buckets");
8350Sstevel@tonic-gate 	mp->buckets = kobj_zalloc(mp->hashsize * sizeof (symid_t), KM_WAIT);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	mp->text = _text;
8380Sstevel@tonic-gate 	mp->data = _data;
8393446Smrj 
8403446Smrj 	mp->text_size = _etext - _text;
8413446Smrj 	mp->data_size = _edata - _data;
8423446Smrj 
8430Sstevel@tonic-gate 	cp->mod_text = mp->text;
8440Sstevel@tonic-gate 	cp->mod_text_size = mp->text_size;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	mp->filename = cp->mod_filename;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
8490Sstevel@tonic-gate 	if (kobj_debug & D_LOADING) {
8500Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: file=%s\n", mp->filename);
8510Sstevel@tonic-gate 		_kobj_printf(ops, "\ttext: 0x%p", mp->text);
8520Sstevel@tonic-gate 		_kobj_printf(ops, " size: 0x%x\n", mp->text_size);
8530Sstevel@tonic-gate 		_kobj_printf(ops, "\tdata: 0x%p", mp->data);
8540Sstevel@tonic-gate 		_kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	/*
8590Sstevel@tonic-gate 	 * Insert symbols into the hash table.
8600Sstevel@tonic-gate 	 */
8610Sstevel@tonic-gate 	for (i = 0; i < mp->nsyms; i++) {
8620Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
8650Sstevel@tonic-gate 			continue;
8660Sstevel@tonic-gate #ifdef	__sparc
8670Sstevel@tonic-gate 		/*
8680Sstevel@tonic-gate 		 * Register symbols are ignored in the kernel
8690Sstevel@tonic-gate 		 */
8700Sstevel@tonic-gate 		if (ELF_ST_TYPE(sp->st_info) == STT_SPARC_REGISTER)
8710Sstevel@tonic-gate 			continue;
8720Sstevel@tonic-gate #endif	/* __sparc */
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		sym_insert(mp, mp->strings + sp->st_name, i);
8750Sstevel@tonic-gate 	}
8760Sstevel@tonic-gate 
8773446Smrj 	KOBJ_MARK("load_exec done");
8780Sstevel@tonic-gate 	return (mp);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate /*
8823446Smrj  * Set up the linker module (if it's compiled in, LDNAME is NULL)
8830Sstevel@tonic-gate  */
8840Sstevel@tonic-gate static void
8850Sstevel@tonic-gate load_linker(val_t *bootaux)
8860Sstevel@tonic-gate {
8870Sstevel@tonic-gate 	struct module *kmp = (struct module *)kobj_modules->mod_mp;
8880Sstevel@tonic-gate 	struct module *mp;
8890Sstevel@tonic-gate 	struct modctl *cp;
8900Sstevel@tonic-gate 	int i;
8910Sstevel@tonic-gate 	Shdr *shp;
8920Sstevel@tonic-gate 	Sym *sp;
8930Sstevel@tonic-gate 	int shsize;
8940Sstevel@tonic-gate 	char *dlname = (char *)bootaux[BA_LDNAME].ba_ptr;
8950Sstevel@tonic-gate 
8963446Smrj 	/*
8973446Smrj 	 * On some architectures, krtld is compiled into the kernel.
8983446Smrj 	 */
8993446Smrj 	if (dlname == NULL)
9003446Smrj 		return;
9013446Smrj 
9020Sstevel@tonic-gate 	cp = add_primary(dlname, KOBJ_LM_PRIMARY);
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	cp->mod_mp = mp;
9070Sstevel@tonic-gate 	mp->hdr = *(Ehdr *)bootaux[BA_LDELF].ba_ptr;
9080Sstevel@tonic-gate 	shsize = mp->hdr.e_shentsize * mp->hdr.e_shnum;
9090Sstevel@tonic-gate 	mp->shdrs = kobj_alloc(shsize, KM_WAIT);
9100Sstevel@tonic-gate 	bcopy(bootaux[BA_LDSHDR].ba_ptr, mp->shdrs, shsize);
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	for (i = 1; i < (int)mp->hdr.e_shnum; i++) {
9130Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + (i * mp->hdr.e_shentsize));
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 		if (shp->sh_flags & SHF_ALLOC) {
9160Sstevel@tonic-gate 			if (shp->sh_flags & SHF_WRITE) {
9170Sstevel@tonic-gate 				if (mp->data == NULL)
9180Sstevel@tonic-gate 					mp->data = (char *)shp->sh_addr;
9190Sstevel@tonic-gate 			} else if (mp->text == NULL) {
9200Sstevel@tonic-gate 				mp->text = (char *)shp->sh_addr;
9210Sstevel@tonic-gate 			}
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 		if (shp->sh_type == SHT_SYMTAB) {
9240Sstevel@tonic-gate 			mp->symtbl_section = i;
9250Sstevel@tonic-gate 			mp->symhdr = shp;
9260Sstevel@tonic-gate 			mp->symspace = mp->symtbl = (char *)shp->sh_addr;
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 	}
9290Sstevel@tonic-gate 	mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
9300Sstevel@tonic-gate 	mp->flags = KOBJ_INTERP|KOBJ_PRIM;
9310Sstevel@tonic-gate 	mp->strhdr = (Shdr *)
9323912Slling 	    (mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
9330Sstevel@tonic-gate 	mp->strings = (char *)mp->strhdr->sh_addr;
9340Sstevel@tonic-gate 	mp->hashsize = kobj_gethashsize(mp->nsyms);
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	mp->symsize = mp->symhdr->sh_size + mp->strhdr->sh_size + sizeof (int) +
9373912Slling 	    (mp->hashsize + mp->nsyms) * sizeof (symid_t);
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 	mp->chains = kobj_zalloc(mp->nsyms * sizeof (symid_t), KM_WAIT);
9400Sstevel@tonic-gate 	mp->buckets = kobj_zalloc(mp->hashsize * sizeof (symid_t), KM_WAIT);
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	mp->bss = bootaux[BA_BSS].ba_val;
9430Sstevel@tonic-gate 	mp->bss_align = 0;	/* pre-aligned during allocation */
9440Sstevel@tonic-gate 	mp->bss_size = (uintptr_t)_edata - mp->bss;
9450Sstevel@tonic-gate 	mp->text_size = _etext - mp->text;
9460Sstevel@tonic-gate 	mp->data_size = _edata - mp->data;
9470Sstevel@tonic-gate 	mp->filename = cp->mod_filename;
9480Sstevel@tonic-gate 	cp->mod_text = mp->text;
9490Sstevel@tonic-gate 	cp->mod_text_size = mp->text_size;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	/*
9520Sstevel@tonic-gate 	 * Now that we've figured out where the linker is,
9530Sstevel@tonic-gate 	 * set the limits for the booted object.
9540Sstevel@tonic-gate 	 */
9550Sstevel@tonic-gate 	kmp->text_size = (size_t)(mp->text - kmp->text);
9560Sstevel@tonic-gate 	kmp->data_size = (size_t)(mp->data - kmp->data);
9570Sstevel@tonic-gate 	kobj_modules->mod_text_size = kmp->text_size;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
9600Sstevel@tonic-gate 	if (kobj_debug & D_LOADING) {
9610Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: file=%s\n", mp->filename);
9620Sstevel@tonic-gate 		_kobj_printf(ops, "\ttext:0x%p", mp->text);
9630Sstevel@tonic-gate 		_kobj_printf(ops, " size: 0x%x\n", mp->text_size);
9640Sstevel@tonic-gate 		_kobj_printf(ops, "\tdata:0x%p", mp->data);
9650Sstevel@tonic-gate 		_kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	/*
9700Sstevel@tonic-gate 	 * Insert the symbols into the hash table.
9710Sstevel@tonic-gate 	 */
9720Sstevel@tonic-gate 	for (i = 0; i < mp->nsyms; i++) {
9730Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
9760Sstevel@tonic-gate 			continue;
9770Sstevel@tonic-gate 		if (ELF_ST_BIND(sp->st_info) == STB_GLOBAL) {
9780Sstevel@tonic-gate 			if (sp->st_shndx == SHN_COMMON)
9790Sstevel@tonic-gate 				sp->st_shndx = SHN_ABS;
9800Sstevel@tonic-gate 		}
9810Sstevel@tonic-gate 		sym_insert(mp, mp->strings + sp->st_name, i);
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate static kobj_notify_list_t **
9870Sstevel@tonic-gate kobj_notify_lookup(uint_t type)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	ASSERT(type != 0 && type < sizeof (kobj_notifiers) /
9900Sstevel@tonic-gate 	    sizeof (kobj_notify_list_t *));
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	return (&kobj_notifiers[type]);
9930Sstevel@tonic-gate }
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate int
9960Sstevel@tonic-gate kobj_notify_add(kobj_notify_list_t *knp)
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate 	kobj_notify_list_t **knl;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	knl = kobj_notify_lookup(knp->kn_type);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	knp->kn_next = NULL;
10030Sstevel@tonic-gate 	knp->kn_prev = NULL;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	mutex_enter(&kobj_lock);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (*knl != NULL) {
10080Sstevel@tonic-gate 		(*knl)->kn_prev = knp;
10090Sstevel@tonic-gate 		knp->kn_next = *knl;
10100Sstevel@tonic-gate 	}
10110Sstevel@tonic-gate 	(*knl) = knp;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	mutex_exit(&kobj_lock);
10140Sstevel@tonic-gate 	return (0);
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate int
10180Sstevel@tonic-gate kobj_notify_remove(kobj_notify_list_t *knp)
10190Sstevel@tonic-gate {
10200Sstevel@tonic-gate 	kobj_notify_list_t **knl = kobj_notify_lookup(knp->kn_type);
10210Sstevel@tonic-gate 	kobj_notify_list_t *tknp;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	mutex_enter(&kobj_lock);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	/* LINTED */
10260Sstevel@tonic-gate 	if (tknp = knp->kn_next)
10270Sstevel@tonic-gate 		tknp->kn_prev = knp->kn_prev;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	/* LINTED */
10300Sstevel@tonic-gate 	if (tknp = knp->kn_prev)
10310Sstevel@tonic-gate 		tknp->kn_next = knp->kn_next;
10320Sstevel@tonic-gate 	else
10330Sstevel@tonic-gate 		*knl = knp->kn_next;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	mutex_exit(&kobj_lock);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	return (0);
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate /*
10410Sstevel@tonic-gate  * Notify all interested callbacks of a specified change in module state.
10420Sstevel@tonic-gate  */
10430Sstevel@tonic-gate static void
10440Sstevel@tonic-gate kobj_notify(int type, struct modctl *modp)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	kobj_notify_list_t *knp;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	if (modp->mod_loadflags & MOD_NONOTIFY || standalone)
10490Sstevel@tonic-gate 		return;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	mutex_enter(&kobj_lock);
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	for (knp = *(kobj_notify_lookup(type)); knp != NULL; knp = knp->kn_next)
10540Sstevel@tonic-gate 		knp->kn_func(type, modp);
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 	/*
10570Sstevel@tonic-gate 	 * KDI notification must be last (it has to allow for work done by the
10580Sstevel@tonic-gate 	 * other notification callbacks), so we call it manually.
10590Sstevel@tonic-gate 	 */
10600Sstevel@tonic-gate 	kobj_kdi_mod_notify(type, modp);
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	mutex_exit(&kobj_lock);
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate /*
10660Sstevel@tonic-gate  * Ask boot for the module path.
10670Sstevel@tonic-gate  */
10683446Smrj /*ARGSUSED*/
10690Sstevel@tonic-gate static char *
10703446Smrj getmodpath(const char *filename)
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate 	char *path;
10730Sstevel@tonic-gate 	int len;
10740Sstevel@tonic-gate 
10753446Smrj #if defined(_UNIX_KRTLD)
10763446Smrj 	/*
10773446Smrj 	 * The boot program provides the module name when it detects
10783446Smrj 	 * that the executable has an interpreter, thus we can ask
10793446Smrj 	 * it directly in this case.
10803446Smrj 	 */
10810Sstevel@tonic-gate 	if ((len = BOP_GETPROPLEN(ops, MODPATH_PROPNAME)) == -1)
10820Sstevel@tonic-gate 		return (MOD_DEFPATH);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	path = kobj_zalloc(len, KM_WAIT);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	(void) BOP_GETPROP(ops, MODPATH_PROPNAME, path);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	return (*path ? path : MOD_DEFPATH);
10893446Smrj 
10903446Smrj #else
10913446Smrj 
10923446Smrj 	/*
10933446Smrj 	 * Construct the directory path from the filename.
10943446Smrj 	 */
10953446Smrj 
10963446Smrj 	char *p;
10973446Smrj 	const char isastr[] = "/amd64";
10983446Smrj 	size_t isalen = strlen(isastr);
10993446Smrj 
11003446Smrj 	if ((p = strrchr(filename, '/')) == NULL)
11013446Smrj 		return (MOD_DEFPATH);
11023446Smrj 
11033446Smrj 	while (p > filename && *(p - 1) == '/')
11043446Smrj 		p--;	/* remove trailing '/' characters */
11053446Smrj 	if (p == filename)
11063446Smrj 		p++;	/* so "/" -is- the modpath in this case */
11073446Smrj 
11083446Smrj 	/*
11093446Smrj 	 * Remove optional isa-dependent directory name - the module
11103446Smrj 	 * subsystem will put this back again (!)
11113446Smrj 	 */
11123446Smrj 	len = p - filename;
11133446Smrj 	if (len > isalen &&
11143446Smrj 	    strncmp(&filename[len - isalen], isastr, isalen) == 0)
11153446Smrj 		p -= isalen;
11163446Smrj 
11173446Smrj 	/*
11183446Smrj 	 * "/platform/mumblefrotz" + " " + MOD_DEFPATH
11193446Smrj 	 */
11203446Smrj 	len += (p - filename) + 1 + strlen(MOD_DEFPATH) + 1;
11213446Smrj 
11223446Smrj 	path = kobj_zalloc(len, KM_WAIT);
11233446Smrj 	(void) strncpy(path, filename, p - filename);
11243446Smrj 	(void) strcat(path, " ");
11253446Smrj 	return (strcat(path, MOD_DEFPATH));
11263446Smrj #endif
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate static struct modctl *
11303446Smrj add_primary(const char *filename, int lmid)
11310Sstevel@tonic-gate {
11320Sstevel@tonic-gate 	struct modctl *cp;
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	cp = kobj_zalloc(sizeof (struct modctl), KM_WAIT);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	cp->mod_filename = kobj_alloc(strlen(filename) + 1, KM_WAIT);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	/*
11390Sstevel@tonic-gate 	 * For symbol lookup, we assemble our own
11400Sstevel@tonic-gate 	 * modctl list of the primary modules.
11410Sstevel@tonic-gate 	 */
11420Sstevel@tonic-gate 
11430Sstevel@tonic-gate 	(void) strcpy(cp->mod_filename, filename);
11440Sstevel@tonic-gate 	cp->mod_modname = basename(cp->mod_filename);
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	/* set values for modinfo assuming that the load will work */
11470Sstevel@tonic-gate 	cp->mod_prim = 1;
11480Sstevel@tonic-gate 	cp->mod_loaded = 1;
11490Sstevel@tonic-gate 	cp->mod_installed = 1;
11500Sstevel@tonic-gate 	cp->mod_loadcnt = 1;
11510Sstevel@tonic-gate 	cp->mod_loadflags = MOD_NOAUTOUNLOAD;
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	cp->mod_id = kobj_last_module_id++;
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/*
11560Sstevel@tonic-gate 	 * Link the module in. We'll pass this info on
11570Sstevel@tonic-gate 	 * to the mod squad later.
11580Sstevel@tonic-gate 	 */
11590Sstevel@tonic-gate 	if (kobj_modules == NULL) {
11600Sstevel@tonic-gate 		kobj_modules = cp;
11610Sstevel@tonic-gate 		cp->mod_prev = cp->mod_next = cp;
11620Sstevel@tonic-gate 	} else {
11630Sstevel@tonic-gate 		cp->mod_prev = kobj_modules->mod_prev;
11640Sstevel@tonic-gate 		cp->mod_next = kobj_modules;
11650Sstevel@tonic-gate 		kobj_modules->mod_prev->mod_next = cp;
11660Sstevel@tonic-gate 		kobj_modules->mod_prev = cp;
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	kobj_lm_append(lmid, cp);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	return (cp);
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate static int
11750Sstevel@tonic-gate bind_primary(val_t *bootaux, int lmid)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	struct modctl_list *linkmap = kobj_lm_lookup(lmid);
11780Sstevel@tonic-gate 	struct modctl_list *lp;
11790Sstevel@tonic-gate 	struct module *mp;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	/*
11820Sstevel@tonic-gate 	 * Do common symbols.
11830Sstevel@tonic-gate 	 */
11840Sstevel@tonic-gate 	for (lp = linkmap; lp; lp = lp->modl_next) {
11850Sstevel@tonic-gate 		mp = mod(lp);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		/*
11880Sstevel@tonic-gate 		 * Don't do common section relocations for modules that
11890Sstevel@tonic-gate 		 * don't need it.
11900Sstevel@tonic-gate 		 */
11910Sstevel@tonic-gate 		if (mp->flags & (KOBJ_EXEC|KOBJ_INTERP))
11920Sstevel@tonic-gate 			continue;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		if (do_common(mp) < 0)
11950Sstevel@tonic-gate 			return (-1);
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/*
11990Sstevel@tonic-gate 	 * Resolve symbols.
12000Sstevel@tonic-gate 	 */
12010Sstevel@tonic-gate 	for (lp = linkmap; lp; lp = lp->modl_next) {
12020Sstevel@tonic-gate 		mp = mod(lp);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		if (do_symbols(mp, 0) < 0)
12050Sstevel@tonic-gate 			return (-1);
12060Sstevel@tonic-gate 	}
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	/*
12090Sstevel@tonic-gate 	 * Do relocations.
12100Sstevel@tonic-gate 	 */
12110Sstevel@tonic-gate 	for (lp = linkmap; lp; lp = lp->modl_next) {
12120Sstevel@tonic-gate 		mp = mod(lp);
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		if (mp->flags & KOBJ_EXEC) {
12153446Smrj 			Dyn *dyn;
12163446Smrj 			Word relasz = 0, relaent = 0;
12173446Smrj 			Word shtype;
12183446Smrj 			char *rela = NULL;
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 			for (dyn = (Dyn *)bootaux[BA_DYNAMIC].ba_ptr;
12210Sstevel@tonic-gate 			    dyn->d_tag != DT_NULL; dyn++) {
12220Sstevel@tonic-gate 				switch (dyn->d_tag) {
12230Sstevel@tonic-gate 				case DT_RELASZ:
12240Sstevel@tonic-gate 				case DT_RELSZ:
12250Sstevel@tonic-gate 					relasz = dyn->d_un.d_val;
12260Sstevel@tonic-gate 					break;
12270Sstevel@tonic-gate 				case DT_RELAENT:
12280Sstevel@tonic-gate 				case DT_RELENT:
12290Sstevel@tonic-gate 					relaent = dyn->d_un.d_val;
12300Sstevel@tonic-gate 					break;
12310Sstevel@tonic-gate 				case DT_RELA:
12320Sstevel@tonic-gate 					shtype = SHT_RELA;
12330Sstevel@tonic-gate 					rela = (char *)(dyn->d_un.d_ptr +
12343912Slling 					    dynseg);
12350Sstevel@tonic-gate 					break;
12360Sstevel@tonic-gate 				case DT_REL:
12370Sstevel@tonic-gate 					shtype = SHT_REL;
12380Sstevel@tonic-gate 					rela = (char *)(dyn->d_un.d_ptr +
12393912Slling 					    dynseg);
12400Sstevel@tonic-gate 					break;
12410Sstevel@tonic-gate 				}
12420Sstevel@tonic-gate 			}
12430Sstevel@tonic-gate 			if (relasz == 0 ||
12440Sstevel@tonic-gate 			    relaent == 0 || rela == NULL) {
12450Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: bind_primary(): "
12460Sstevel@tonic-gate 				    "no relocation information found for "
12470Sstevel@tonic-gate 				    "module %s\n", mp->filename);
12480Sstevel@tonic-gate 				return (-1);
12490Sstevel@tonic-gate 			}
12500Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
12510Sstevel@tonic-gate 			if (kobj_debug & D_RELOCATIONS)
12520Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: relocating: file=%s "
12530Sstevel@tonic-gate 				    "KOBJ_EXEC\n", mp->filename);
12540Sstevel@tonic-gate #endif
12550Sstevel@tonic-gate 			if (do_relocate(mp, rela, shtype, relasz/relaent,
12560Sstevel@tonic-gate 			    relaent, (Addr)mp->text) < 0)
12570Sstevel@tonic-gate 				return (-1);
12580Sstevel@tonic-gate 		} else {
12590Sstevel@tonic-gate 			if (do_relocations(mp) < 0)
12600Sstevel@tonic-gate 				return (-1);
12610Sstevel@tonic-gate 		}
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		kobj_sync_instruction_memory(mp->text, mp->text_size);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	for (lp = linkmap; lp; lp = lp->modl_next) {
12670Sstevel@tonic-gate 		mp = mod(lp);
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 		/*
12700Sstevel@tonic-gate 		 * We need to re-read the full symbol table for the boot file,
12710Sstevel@tonic-gate 		 * since we couldn't use the full one before.  We also need to
12720Sstevel@tonic-gate 		 * load the CTF sections of both the boot file and the
12730Sstevel@tonic-gate 		 * interpreter (us).
12740Sstevel@tonic-gate 		 */
12750Sstevel@tonic-gate 		if (mp->flags & KOBJ_EXEC) {
12760Sstevel@tonic-gate 			struct _buf *file;
12770Sstevel@tonic-gate 			int n;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 			file = kobj_open_file(mp->filename);
12800Sstevel@tonic-gate 			if (file == (struct _buf *)-1)
12810Sstevel@tonic-gate 				return (-1);
12820Sstevel@tonic-gate 			if (kobj_read_file(file, (char *)&mp->hdr,
12830Sstevel@tonic-gate 			    sizeof (mp->hdr), 0) < 0)
12840Sstevel@tonic-gate 				return (-1);
12850Sstevel@tonic-gate 			n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
12860Sstevel@tonic-gate 			mp->shdrs = kobj_alloc(n, KM_WAIT);
12870Sstevel@tonic-gate 			if (kobj_read_file(file, mp->shdrs, n,
12880Sstevel@tonic-gate 			    mp->hdr.e_shoff) < 0)
12890Sstevel@tonic-gate 				return (-1);
12900Sstevel@tonic-gate 			if (get_syms(mp, file) < 0)
12910Sstevel@tonic-gate 				return (-1);
12920Sstevel@tonic-gate 			if (get_ctf(mp, file) < 0)
12930Sstevel@tonic-gate 				return (-1);
12940Sstevel@tonic-gate 			kobj_close_file(file);
12950Sstevel@tonic-gate 			mp->flags |= KOBJ_RELOCATED;
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 		} else if (mp->flags & KOBJ_INTERP) {
12980Sstevel@tonic-gate 			struct _buf *file;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 			/*
13010Sstevel@tonic-gate 			 * The interpreter path fragment in mp->filename
13020Sstevel@tonic-gate 			 * will already have the module directory suffix
13030Sstevel@tonic-gate 			 * in it (if appropriate).
13040Sstevel@tonic-gate 			 */
13050Sstevel@tonic-gate 			file = kobj_open_path(mp->filename, 1, 0);
13060Sstevel@tonic-gate 			if (file == (struct _buf *)-1)
13070Sstevel@tonic-gate 				return (-1);
13080Sstevel@tonic-gate 			if (get_ctf(mp, file) < 0)
13090Sstevel@tonic-gate 				return (-1);
13100Sstevel@tonic-gate 			kobj_close_file(file);
13110Sstevel@tonic-gate 			mp->flags |= KOBJ_RELOCATED;
13120Sstevel@tonic-gate 		}
13130Sstevel@tonic-gate 	}
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	return (0);
13160Sstevel@tonic-gate }
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate static struct modctl *
13190Sstevel@tonic-gate mod_already_loaded(char *modname)
13200Sstevel@tonic-gate {
13210Sstevel@tonic-gate 	struct modctl *mctl = kobj_modules;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	do {
13240Sstevel@tonic-gate 		if (strcmp(modname, mctl->mod_filename) == 0)
13250Sstevel@tonic-gate 			return (mctl);
13260Sstevel@tonic-gate 		mctl = mctl->mod_next;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	} while (mctl != kobj_modules);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	return (NULL);
13310Sstevel@tonic-gate }
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate /*
13340Sstevel@tonic-gate  * Load all the primary dependent modules.
13350Sstevel@tonic-gate  */
13360Sstevel@tonic-gate static int
13370Sstevel@tonic-gate load_primary(struct module *mp, int lmid)
13380Sstevel@tonic-gate {
13390Sstevel@tonic-gate 	struct modctl *cp;
13400Sstevel@tonic-gate 	struct module *dmp;
13410Sstevel@tonic-gate 	char *p, *q;
13420Sstevel@tonic-gate 	char modname[MODMAXNAMELEN];
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	if ((p = mp->depends_on) == NULL)
13450Sstevel@tonic-gate 		return (0);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	/* CONSTANTCONDITION */
13480Sstevel@tonic-gate 	while (1) {
13490Sstevel@tonic-gate 		/*
13500Sstevel@tonic-gate 		 * Skip space.
13510Sstevel@tonic-gate 		 */
13520Sstevel@tonic-gate 		while (*p && (*p == ' ' || *p == '\t'))
13530Sstevel@tonic-gate 			p++;
13540Sstevel@tonic-gate 		/*
13550Sstevel@tonic-gate 		 * Get module name.
13560Sstevel@tonic-gate 		 */
13570Sstevel@tonic-gate 		q = modname;
13580Sstevel@tonic-gate 		while (*p && *p != ' ' && *p != '\t')
13590Sstevel@tonic-gate 			*q++ = *p++;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 		if (q == modname)
13620Sstevel@tonic-gate 			break;
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 		*q = '\0';
13650Sstevel@tonic-gate 		/*
13660Sstevel@tonic-gate 		 * Check for dup dependencies.
13670Sstevel@tonic-gate 		 */
13680Sstevel@tonic-gate 		if (strcmp(modname, "dtracestubs") == 0 ||
13690Sstevel@tonic-gate 		    mod_already_loaded(modname) != NULL)
13700Sstevel@tonic-gate 			continue;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 		cp = add_primary(modname, lmid);
13730Sstevel@tonic-gate 		cp->mod_busy = 1;
13740Sstevel@tonic-gate 		/*
13750Sstevel@tonic-gate 		 * Load it.
13760Sstevel@tonic-gate 		 */
13770Sstevel@tonic-gate 		(void) kobj_load_module(cp, 1);
13780Sstevel@tonic-gate 		cp->mod_busy = 0;
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 		if ((dmp = cp->mod_mp) == NULL) {
13810Sstevel@tonic-gate 			cp->mod_loaded = 0;
13820Sstevel@tonic-gate 			cp->mod_installed = 0;
13830Sstevel@tonic-gate 			cp->mod_loadcnt = 0;
13840Sstevel@tonic-gate 			return (-1);
13850Sstevel@tonic-gate 		}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 		add_dependent(mp, dmp);
13880Sstevel@tonic-gate 		dmp->flags |= KOBJ_PRIM;
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		/*
13910Sstevel@tonic-gate 		 * Recurse.
13920Sstevel@tonic-gate 		 */
13930Sstevel@tonic-gate 		if (load_primary(dmp, lmid) == -1) {
13940Sstevel@tonic-gate 			cp->mod_loaded = 0;
13950Sstevel@tonic-gate 			cp->mod_installed = 0;
13960Sstevel@tonic-gate 			cp->mod_loadcnt = 0;
13970Sstevel@tonic-gate 			return (-1);
13980Sstevel@tonic-gate 		}
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 	return (0);
14010Sstevel@tonic-gate }
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate static int
14042191Sszhou console_is_usb_serial(void)
14052191Sszhou {
14062191Sszhou 	char *console;
14072191Sszhou 	int len, ret;
14082191Sszhou 
14092191Sszhou 	if ((len = BOP_GETPROPLEN(ops, "console")) == -1)
14102191Sszhou 		return (0);
14112191Sszhou 
14122191Sszhou 	console = kobj_zalloc(len, KM_WAIT|KM_TMP);
14132191Sszhou 	(void) BOP_GETPROP(ops, "console", console);
14142191Sszhou 	ret = (strcmp(console, "usb-serial") == 0);
14152191Sszhou 	kobj_free(console, len);
14162191Sszhou 
14172191Sszhou 	return (ret);
14182191Sszhou }
14192191Sszhou 
14202191Sszhou static int
14210Sstevel@tonic-gate load_kmdb(val_t *bootaux)
14220Sstevel@tonic-gate {
14230Sstevel@tonic-gate 	struct modctl *mctl;
14240Sstevel@tonic-gate 	struct module *mp;
14250Sstevel@tonic-gate 	Sym *sym;
14260Sstevel@tonic-gate 
14272191Sszhou 	if (console_is_usb_serial()) {
14282191Sszhou 		_kobj_printf(ops, "kmdb not loaded "
14292191Sszhou 		    "(unsupported on usb serial console)\n");
14302191Sszhou 		return (0);
14312191Sszhou 	}
14322191Sszhou 
14330Sstevel@tonic-gate 	_kobj_printf(ops, "Loading kmdb...\n");
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	if ((mctl = add_primary("misc/kmdbmod", KOBJ_LM_DEBUGGER)) == NULL)
14360Sstevel@tonic-gate 		return (-1);
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	mctl->mod_busy = 1;
14390Sstevel@tonic-gate 	(void) kobj_load_module(mctl, 1);
14400Sstevel@tonic-gate 	mctl->mod_busy = 0;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	if ((mp = mctl->mod_mp) == NULL)
14430Sstevel@tonic-gate 		return (-1);
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	mp->flags |= KOBJ_PRIM;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	if (load_primary(mp, KOBJ_LM_DEBUGGER) < 0)
14480Sstevel@tonic-gate 		return (-1);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	if (boothowto & RB_VERBOSE)
14510Sstevel@tonic-gate 		kobj_lm_dump(KOBJ_LM_DEBUGGER);
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	if (bind_primary(bootaux, KOBJ_LM_DEBUGGER) < 0)
14540Sstevel@tonic-gate 		return (-1);
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 	if ((sym = lookup_one(mctl->mod_mp, "kctl_boot_activate")) == NULL)
14570Sstevel@tonic-gate 		return (-1);
14580Sstevel@tonic-gate 
14593446Smrj #ifdef	KOBJ_DEBUG
14603446Smrj 	if (kobj_debug & D_DEBUG) {
14613446Smrj 		_kobj_printf(ops, "calling kctl_boot_activate() @ 0x%lx\n",
14623446Smrj 		    sym->st_value);
14633446Smrj 		_kobj_printf(ops, "\tops 0x%p\n", ops);
14643446Smrj 		_kobj_printf(ops, "\tromp 0x%p\n", romp);
14653446Smrj 	}
14663446Smrj #endif
14673446Smrj 
14680Sstevel@tonic-gate 	if (((kctl_boot_activate_f *)sym->st_value)(ops, romp, 0,
14690Sstevel@tonic-gate 	    (const char **)kobj_kmdb_argv) < 0)
14700Sstevel@tonic-gate 		return (-1);
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 	return (0);
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate /*
14760Sstevel@tonic-gate  * Return a string listing module dependencies.
14770Sstevel@tonic-gate  */
14780Sstevel@tonic-gate static char *
14790Sstevel@tonic-gate depends_on(struct module *mp)
14800Sstevel@tonic-gate {
14810Sstevel@tonic-gate 	Sym *sp;
14820Sstevel@tonic-gate 	char *depstr, *q;
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	/*
14850Sstevel@tonic-gate 	 * The module doesn't have a depends_on value, so let's try it the
14860Sstevel@tonic-gate 	 * old-fashioned way - via "_depends_on"
14870Sstevel@tonic-gate 	 */
14880Sstevel@tonic-gate 	if ((sp = lookup_one(mp, "_depends_on")) == NULL)
14890Sstevel@tonic-gate 		return (NULL);
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	q = (char *)sp->st_value;
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	/*
14940Sstevel@tonic-gate 	 * Idiot checks. Make sure it's
14950Sstevel@tonic-gate 	 * in-bounds and NULL terminated.
14960Sstevel@tonic-gate 	 */
14970Sstevel@tonic-gate 	if (kobj_addrcheck(mp, q) || q[sp->st_size - 1] != '\0') {
14980Sstevel@tonic-gate 		_kobj_printf(ops, "Error processing dependency for %s\n",
14990Sstevel@tonic-gate 		    mp->filename);
15000Sstevel@tonic-gate 		return (NULL);
15010Sstevel@tonic-gate 	}
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	depstr = (char *)kobj_alloc(strlen(q) + 1, KM_WAIT);
15040Sstevel@tonic-gate 	(void) strcpy(depstr, q);
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	return (depstr);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate void
15100Sstevel@tonic-gate kobj_getmodinfo(void *xmp, struct modinfo *modinfo)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate 	struct module *mp;
15130Sstevel@tonic-gate 	mp = (struct module *)xmp;
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	modinfo->mi_base = mp->text;
15160Sstevel@tonic-gate 	modinfo->mi_size = mp->text_size + mp->data_size;
15170Sstevel@tonic-gate }
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate /*
15200Sstevel@tonic-gate  * kobj_export_ksyms() performs the following services:
15210Sstevel@tonic-gate  *
15220Sstevel@tonic-gate  * (1) Migrates the symbol table from boot/kobj memory to the ksyms arena.
15230Sstevel@tonic-gate  * (2) Removes unneeded symbols to save space.
15240Sstevel@tonic-gate  * (3) Reduces memory footprint by using VM_BESTFIT allocations.
15250Sstevel@tonic-gate  * (4) Makes the symbol table visible to /dev/ksyms.
15260Sstevel@tonic-gate  */
15270Sstevel@tonic-gate static void
15280Sstevel@tonic-gate kobj_export_ksyms(struct module *mp)
15290Sstevel@tonic-gate {
15300Sstevel@tonic-gate 	Sym *esp = (Sym *)(mp->symtbl + mp->symhdr->sh_size);
15310Sstevel@tonic-gate 	Sym *sp, *osp;
15320Sstevel@tonic-gate 	char *name;
15330Sstevel@tonic-gate 	size_t namelen;
15340Sstevel@tonic-gate 	struct module *omp;
15350Sstevel@tonic-gate 	uint_t nsyms;
15360Sstevel@tonic-gate 	size_t symsize = mp->symhdr->sh_entsize;
15370Sstevel@tonic-gate 	size_t locals = 1;
15380Sstevel@tonic-gate 	size_t strsize;
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	/*
15410Sstevel@tonic-gate 	 * Make a copy of the original module structure.
15420Sstevel@tonic-gate 	 */
15430Sstevel@tonic-gate 	omp = kobj_alloc(sizeof (struct module), KM_WAIT);
15440Sstevel@tonic-gate 	bcopy(mp, omp, sizeof (struct module));
15450Sstevel@tonic-gate 
15460Sstevel@tonic-gate 	/*
15470Sstevel@tonic-gate 	 * Compute the sizes of the new symbol table sections.
15480Sstevel@tonic-gate 	 */
15490Sstevel@tonic-gate 	for (nsyms = strsize = 1, osp = (Sym *)omp->symtbl; osp < esp; osp++) {
15500Sstevel@tonic-gate 		if (osp->st_value == 0)
15510Sstevel@tonic-gate 			continue;
15520Sstevel@tonic-gate 		if (sym_lookup(omp, osp) == NULL)
15530Sstevel@tonic-gate 			continue;
15540Sstevel@tonic-gate 		name = omp->strings + osp->st_name;
15550Sstevel@tonic-gate 		namelen = strlen(name);
15560Sstevel@tonic-gate 		if (ELF_ST_BIND(osp->st_info) == STB_LOCAL)
15570Sstevel@tonic-gate 			locals++;
15580Sstevel@tonic-gate 		nsyms++;
15590Sstevel@tonic-gate 		strsize += namelen + 1;
15600Sstevel@tonic-gate 	}
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	mp->nsyms = nsyms;
15630Sstevel@tonic-gate 	mp->hashsize = kobj_gethashsize(mp->nsyms);
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	/*
15660Sstevel@tonic-gate 	 * ksyms_lock must be held as writer during any operation that
15670Sstevel@tonic-gate 	 * modifies ksyms_arena, including allocation from same, and
15680Sstevel@tonic-gate 	 * must not be dropped until the arena is vmem_walk()able.
15690Sstevel@tonic-gate 	 */
15700Sstevel@tonic-gate 	rw_enter(&ksyms_lock, RW_WRITER);
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	/*
15730Sstevel@tonic-gate 	 * Allocate space for the new section headers (symtab and strtab),
15740Sstevel@tonic-gate 	 * symbol table, buckets, chains, and strings.
15750Sstevel@tonic-gate 	 */
15760Sstevel@tonic-gate 	mp->symsize = (2 * sizeof (Shdr)) + (nsyms * symsize) +
15770Sstevel@tonic-gate 	    (mp->hashsize + mp->nsyms) * sizeof (symid_t) + strsize;
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	if (mp->flags & KOBJ_NOKSYMS) {
15800Sstevel@tonic-gate 		mp->symspace = kobj_alloc(mp->symsize, KM_WAIT);
15810Sstevel@tonic-gate 	} else {
15820Sstevel@tonic-gate 		mp->symspace = vmem_alloc(ksyms_arena, mp->symsize,
15830Sstevel@tonic-gate 		    VM_BESTFIT | VM_SLEEP);
15840Sstevel@tonic-gate 	}
15850Sstevel@tonic-gate 	bzero(mp->symspace, mp->symsize);
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 	/*
15880Sstevel@tonic-gate 	 * Divvy up symspace.
15890Sstevel@tonic-gate 	 */
15900Sstevel@tonic-gate 	mp->shdrs = mp->symspace;
15910Sstevel@tonic-gate 	mp->symhdr = (Shdr *)mp->shdrs;
15920Sstevel@tonic-gate 	mp->strhdr = (Shdr *)(mp->symhdr + 1);
15930Sstevel@tonic-gate 	mp->symtbl = (char *)(mp->strhdr + 1);
15940Sstevel@tonic-gate 	mp->buckets = (symid_t *)(mp->symtbl + (nsyms * symsize));
15950Sstevel@tonic-gate 	mp->chains = (symid_t *)(mp->buckets + mp->hashsize);
15960Sstevel@tonic-gate 	mp->strings = (char *)(mp->chains + nsyms);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	/*
15990Sstevel@tonic-gate 	 * Fill in the new section headers (symtab and strtab).
16000Sstevel@tonic-gate 	 */
16010Sstevel@tonic-gate 	mp->hdr.e_shnum = 2;
16020Sstevel@tonic-gate 	mp->symtbl_section = 0;
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	mp->symhdr->sh_type = SHT_SYMTAB;
16050Sstevel@tonic-gate 	mp->symhdr->sh_addr = (Addr)mp->symtbl;
16060Sstevel@tonic-gate 	mp->symhdr->sh_size = nsyms * symsize;
16070Sstevel@tonic-gate 	mp->symhdr->sh_link = 1;
16080Sstevel@tonic-gate 	mp->symhdr->sh_info = locals;
16090Sstevel@tonic-gate 	mp->symhdr->sh_addralign = sizeof (Addr);
16100Sstevel@tonic-gate 	mp->symhdr->sh_entsize = symsize;
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	mp->strhdr->sh_type = SHT_STRTAB;
16130Sstevel@tonic-gate 	mp->strhdr->sh_addr = (Addr)mp->strings;
16140Sstevel@tonic-gate 	mp->strhdr->sh_size = strsize;
16150Sstevel@tonic-gate 	mp->strhdr->sh_addralign = 1;
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * Construct the new symbol table.
16190Sstevel@tonic-gate 	 */
16200Sstevel@tonic-gate 	for (nsyms = strsize = 1, osp = (Sym *)omp->symtbl; osp < esp; osp++) {
16210Sstevel@tonic-gate 		if (osp->st_value == 0)
16220Sstevel@tonic-gate 			continue;
16230Sstevel@tonic-gate 		if (sym_lookup(omp, osp) == NULL)
16240Sstevel@tonic-gate 			continue;
16250Sstevel@tonic-gate 		name = omp->strings + osp->st_name;
16260Sstevel@tonic-gate 		namelen = strlen(name);
16270Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + symsize * nsyms);
16280Sstevel@tonic-gate 		bcopy(osp, sp, symsize);
16290Sstevel@tonic-gate 		bcopy(name, mp->strings + strsize, namelen);
16300Sstevel@tonic-gate 		sp->st_name = strsize;
16310Sstevel@tonic-gate 		sym_insert(mp, name, nsyms);
16320Sstevel@tonic-gate 		nsyms++;
16330Sstevel@tonic-gate 		strsize += namelen + 1;
16340Sstevel@tonic-gate 	}
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	rw_exit(&ksyms_lock);
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	/*
16390Sstevel@tonic-gate 	 * Free the old section headers -- we'll never need them again.
16400Sstevel@tonic-gate 	 */
16414515Skchow 	if (!(mp->flags & KOBJ_PRIM)) {
16424515Skchow 		uint_t	shn;
16434515Skchow 		Shdr	*shp;
16444515Skchow 
16454515Skchow 		for (shn = 1; shn < omp->hdr.e_shnum; shn++) {
16464515Skchow 			shp = (Shdr *)(omp->shdrs + shn * omp->hdr.e_shentsize);
16474515Skchow 			switch (shp->sh_type) {
16484515Skchow 			case SHT_RELA:
16494515Skchow 			case SHT_REL:
16504515Skchow 				if (shp->sh_addr != 0) {
16514515Skchow 					kobj_free((void *)shp->sh_addr,
16524515Skchow 					    shp->sh_size);
16534515Skchow 				}
16544515Skchow 				break;
16554515Skchow 			}
16564515Skchow 		}
16570Sstevel@tonic-gate 		kobj_free(omp->shdrs, omp->hdr.e_shentsize * omp->hdr.e_shnum);
16584515Skchow 	}
16590Sstevel@tonic-gate 	/*
16600Sstevel@tonic-gate 	 * Discard the old symbol table and our copy of the module strucure.
16610Sstevel@tonic-gate 	 */
16620Sstevel@tonic-gate 	if (!(mp->flags & KOBJ_PRIM))
16630Sstevel@tonic-gate 		kobj_free(omp->symspace, omp->symsize);
16640Sstevel@tonic-gate 	kobj_free(omp, sizeof (struct module));
16650Sstevel@tonic-gate }
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate static void
16680Sstevel@tonic-gate kobj_export_ctf(struct module *mp)
16690Sstevel@tonic-gate {
16700Sstevel@tonic-gate 	char *data = mp->ctfdata;
16710Sstevel@tonic-gate 	size_t size = mp->ctfsize;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	if (data != NULL) {
16740Sstevel@tonic-gate 		if (_moddebug & MODDEBUG_NOCTF) {
16750Sstevel@tonic-gate 			mp->ctfdata = NULL;
16760Sstevel@tonic-gate 			mp->ctfsize = 0;
16770Sstevel@tonic-gate 		} else {
16780Sstevel@tonic-gate 			mp->ctfdata = vmem_alloc(ctf_arena, size,
16790Sstevel@tonic-gate 			    VM_BESTFIT | VM_SLEEP);
16800Sstevel@tonic-gate 			bcopy(data, mp->ctfdata, size);
16810Sstevel@tonic-gate 		}
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 		if (!(mp->flags & KOBJ_PRIM))
16840Sstevel@tonic-gate 			kobj_free(data, size);
16850Sstevel@tonic-gate 	}
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate void
16890Sstevel@tonic-gate kobj_export_module(struct module *mp)
16900Sstevel@tonic-gate {
16910Sstevel@tonic-gate 	kobj_export_ksyms(mp);
16920Sstevel@tonic-gate 	kobj_export_ctf(mp);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 	mp->flags |= KOBJ_EXPORTED;
16950Sstevel@tonic-gate }
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate static int
16980Sstevel@tonic-gate process_dynamic(struct module *mp, char *dyndata, char *strdata)
16990Sstevel@tonic-gate {
17000Sstevel@tonic-gate 	char *path = NULL, *depstr = NULL;
17010Sstevel@tonic-gate 	int allocsize = 0, osize = 0, nsize = 0;
17020Sstevel@tonic-gate 	char *libname, *tmp;
17030Sstevel@tonic-gate 	int lsize;
17040Sstevel@tonic-gate 	Dyn *dynp;
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	for (dynp = (Dyn *)dyndata; dynp && dynp->d_tag != DT_NULL; dynp++) {
17070Sstevel@tonic-gate 		switch (dynp->d_tag) {
17080Sstevel@tonic-gate 		case DT_NEEDED:
17090Sstevel@tonic-gate 			/*
17100Sstevel@tonic-gate 			 * Read the DT_NEEDED entries, expanding the macros they
17110Sstevel@tonic-gate 			 * contain (if any), and concatenating them into a
17120Sstevel@tonic-gate 			 * single space-separated dependency list.
17130Sstevel@tonic-gate 			 */
17140Sstevel@tonic-gate 			libname = (ulong_t)dynp->d_un.d_ptr + strdata;
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 			if (strchr(libname, '$') != NULL) {
17170Sstevel@tonic-gate 				char *_lib;
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 				if (path == NULL)
17200Sstevel@tonic-gate 					path = kobj_alloc(MAXPATHLEN, KM_WAIT);
17210Sstevel@tonic-gate 				if ((_lib = expand_libmacro(libname, path,
17220Sstevel@tonic-gate 				    path)) != NULL)
17230Sstevel@tonic-gate 					libname = _lib;
17240Sstevel@tonic-gate 				else {
17250Sstevel@tonic-gate 					_kobj_printf(ops, "krtld: "
17260Sstevel@tonic-gate 					    "process_dynamic: failed to expand "
17270Sstevel@tonic-gate 					    "%s\n", libname);
17280Sstevel@tonic-gate 				}
17290Sstevel@tonic-gate 			}
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 			lsize = strlen(libname);
17320Sstevel@tonic-gate 			nsize += lsize;
17330Sstevel@tonic-gate 			if (nsize + 1 > allocsize) {
17340Sstevel@tonic-gate 				tmp = kobj_alloc(allocsize + MAXPATHLEN,
17350Sstevel@tonic-gate 				    KM_WAIT);
17360Sstevel@tonic-gate 				if (depstr != NULL) {
17370Sstevel@tonic-gate 					bcopy(depstr, tmp, osize);
17380Sstevel@tonic-gate 					kobj_free(depstr, allocsize);
17390Sstevel@tonic-gate 				}
17400Sstevel@tonic-gate 				depstr = tmp;
17410Sstevel@tonic-gate 				allocsize += MAXPATHLEN;
17420Sstevel@tonic-gate 			}
17430Sstevel@tonic-gate 			bcopy(libname, depstr + osize, lsize);
17440Sstevel@tonic-gate 			*(depstr + nsize) = ' '; /* separator */
17450Sstevel@tonic-gate 			nsize++;
17460Sstevel@tonic-gate 			osize = nsize;
17470Sstevel@tonic-gate 			break;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 		case DT_FLAGS_1:
17500Sstevel@tonic-gate 			if (dynp->d_un.d_val & DF_1_IGNMULDEF)
17510Sstevel@tonic-gate 				mp->flags |= KOBJ_IGNMULDEF;
17520Sstevel@tonic-gate 			if (dynp->d_un.d_val & DF_1_NOKSYMS)
17530Sstevel@tonic-gate 				mp->flags |= KOBJ_NOKSYMS;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 			break;
17560Sstevel@tonic-gate 		}
17570Sstevel@tonic-gate 	}
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 	/*
17600Sstevel@tonic-gate 	 * finish up the depends string (if any)
17610Sstevel@tonic-gate 	 */
17620Sstevel@tonic-gate 	if (depstr != NULL) {
1763*5331Samw 		*(depstr + nsize - 1) = '\0'; /* overwrite separator w/term */
17640Sstevel@tonic-gate 		if (path != NULL)
17650Sstevel@tonic-gate 			kobj_free(path, MAXPATHLEN);
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 		tmp = kobj_alloc(nsize, KM_WAIT);
17680Sstevel@tonic-gate 		bcopy(depstr, tmp, nsize);
17690Sstevel@tonic-gate 		kobj_free(depstr, allocsize);
17700Sstevel@tonic-gate 		depstr = tmp;
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 		mp->depends_on = depstr;
17730Sstevel@tonic-gate 	}
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	return (0);
17760Sstevel@tonic-gate }
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate static int
17790Sstevel@tonic-gate do_dynamic(struct module *mp, struct _buf *file)
17800Sstevel@tonic-gate {
17810Sstevel@tonic-gate 	Shdr *dshp, *dstrp, *shp;
17820Sstevel@tonic-gate 	char *dyndata, *dstrdata;
17830Sstevel@tonic-gate 	int dshn, shn, rc;
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	/* find and validate the dynamic section (if any) */
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	for (dshp = NULL, shn = 1; shn < mp->hdr.e_shnum; shn++) {
17880Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
17890Sstevel@tonic-gate 		switch (shp->sh_type) {
17900Sstevel@tonic-gate 		case SHT_DYNAMIC:
17910Sstevel@tonic-gate 			if (dshp != NULL) {
17920Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: get_dynamic: %s, ",
17930Sstevel@tonic-gate 				    mp->filename);
17940Sstevel@tonic-gate 				_kobj_printf(ops,
17950Sstevel@tonic-gate 				    "multiple dynamic sections\n");
17960Sstevel@tonic-gate 				return (-1);
17970Sstevel@tonic-gate 			} else {
17980Sstevel@tonic-gate 				dshp = shp;
17990Sstevel@tonic-gate 				dshn = shn;
18000Sstevel@tonic-gate 			}
18010Sstevel@tonic-gate 			break;
18020Sstevel@tonic-gate 		}
18030Sstevel@tonic-gate 	}
18040Sstevel@tonic-gate 
18050Sstevel@tonic-gate 	if (dshp == NULL)
18060Sstevel@tonic-gate 		return (0);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	if (dshp->sh_link > mp->hdr.e_shnum) {
18090Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
18100Sstevel@tonic-gate 		_kobj_printf(ops, "no section for sh_link %d\n", dshp->sh_link);
18110Sstevel@tonic-gate 		return (-1);
18120Sstevel@tonic-gate 	}
18130Sstevel@tonic-gate 	dstrp = (Shdr *)(mp->shdrs + dshp->sh_link * mp->hdr.e_shentsize);
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	if (dstrp->sh_type != SHT_STRTAB) {
18160Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
18170Sstevel@tonic-gate 		_kobj_printf(ops, "sh_link not a string table for section %d\n",
18180Sstevel@tonic-gate 		    dshn);
18190Sstevel@tonic-gate 		return (-1);
18200Sstevel@tonic-gate 	}
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate 	/* read it from disk */
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	dyndata = kobj_alloc(dshp->sh_size, KM_WAIT|KM_TMP);
18250Sstevel@tonic-gate 	if (kobj_read_file(file, dyndata, dshp->sh_size, dshp->sh_offset) < 0) {
18260Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
18270Sstevel@tonic-gate 		_kobj_printf(ops, "error reading section %d\n", dshn);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 		kobj_free(dyndata, dshp->sh_size);
18300Sstevel@tonic-gate 		return (-1);
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	dstrdata = kobj_alloc(dstrp->sh_size, KM_WAIT|KM_TMP);
18340Sstevel@tonic-gate 	if (kobj_read_file(file, dstrdata, dstrp->sh_size,
18350Sstevel@tonic-gate 	    dstrp->sh_offset) < 0) {
18360Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_dynamic: %s, ", mp->filename);
18370Sstevel@tonic-gate 		_kobj_printf(ops, "error reading section %d\n", dshp->sh_link);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 		kobj_free(dyndata, dshp->sh_size);
18400Sstevel@tonic-gate 		kobj_free(dstrdata, dstrp->sh_size);
18410Sstevel@tonic-gate 		return (-1);
18420Sstevel@tonic-gate 	}
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	/* pull the interesting pieces out */
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	rc = process_dynamic(mp, dyndata, dstrdata);
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	kobj_free(dyndata, dshp->sh_size);
18490Sstevel@tonic-gate 	kobj_free(dstrdata, dstrp->sh_size);
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	return (rc);
18520Sstevel@tonic-gate }
18530Sstevel@tonic-gate 
18540Sstevel@tonic-gate void
18550Sstevel@tonic-gate kobj_set_ctf(struct module *mp, caddr_t data, size_t size)
18560Sstevel@tonic-gate {
18570Sstevel@tonic-gate 	if (!standalone) {
18580Sstevel@tonic-gate 		if (mp->ctfdata != NULL) {
18590Sstevel@tonic-gate 			if (vmem_contains(ctf_arena, mp->ctfdata,
18603912Slling 			    mp->ctfsize)) {
18610Sstevel@tonic-gate 				vmem_free(ctf_arena, mp->ctfdata, mp->ctfsize);
18620Sstevel@tonic-gate 			} else {
18630Sstevel@tonic-gate 				kobj_free(mp->ctfdata, mp->ctfsize);
18640Sstevel@tonic-gate 			}
18650Sstevel@tonic-gate 		}
18660Sstevel@tonic-gate 	}
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	/*
18690Sstevel@tonic-gate 	 * The order is very important here.  We need to make sure that
18700Sstevel@tonic-gate 	 * consumers, at any given instant, see a consistent state.  We'd
18710Sstevel@tonic-gate 	 * rather they see no CTF data than the address of one buffer and the
18720Sstevel@tonic-gate 	 * size of another.
18730Sstevel@tonic-gate 	 */
18740Sstevel@tonic-gate 	mp->ctfdata = NULL;
18750Sstevel@tonic-gate 	membar_producer();
18760Sstevel@tonic-gate 	mp->ctfsize = size;
18770Sstevel@tonic-gate 	mp->ctfdata = data;
18780Sstevel@tonic-gate 	membar_producer();
18790Sstevel@tonic-gate }
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate int
18820Sstevel@tonic-gate kobj_load_module(struct modctl *modp, int use_path)
18830Sstevel@tonic-gate {
18840Sstevel@tonic-gate 	char *filename = modp->mod_filename;
18850Sstevel@tonic-gate 	char *modname = modp->mod_modname;
18860Sstevel@tonic-gate 	int i;
18870Sstevel@tonic-gate 	int n;
18880Sstevel@tonic-gate 	struct _buf *file;
18890Sstevel@tonic-gate 	struct module *mp = NULL;
18900Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
18910Sstevel@tonic-gate 	int no_suffixdir_drv = 0;
18920Sstevel@tonic-gate #endif
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	mp = kobj_zalloc(sizeof (struct module), KM_WAIT);
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	/*
18970Sstevel@tonic-gate 	 * We need to prevent kmdb's symbols from leaking into /dev/ksyms.
18980Sstevel@tonic-gate 	 * kmdb contains a bunch of symbols with well-known names, symbols
18990Sstevel@tonic-gate 	 * which will mask the real versions, thus causing no end of trouble
19000Sstevel@tonic-gate 	 * for mdb.
19010Sstevel@tonic-gate 	 */
19020Sstevel@tonic-gate 	if (strcmp(modp->mod_modname, "kmdbmod") == 0)
19030Sstevel@tonic-gate 		mp->flags |= KOBJ_NOKSYMS;
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 	file = kobj_open_path(filename, use_path, 1);
19060Sstevel@tonic-gate 	if (file == (struct _buf *)-1) {
19070Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
19080Sstevel@tonic-gate 		file = kobj_open_path(filename, use_path, 0);
19090Sstevel@tonic-gate #endif
19100Sstevel@tonic-gate 		if (file == (struct _buf *)-1) {
19110Sstevel@tonic-gate 			kobj_free(mp, sizeof (*mp));
19120Sstevel@tonic-gate 			goto bad;
19130Sstevel@tonic-gate 		}
19140Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
19150Sstevel@tonic-gate 		/*
19160Sstevel@tonic-gate 		 * There is no driver module in the ISA specific (suffix)
19170Sstevel@tonic-gate 		 * subdirectory but there is a module in the parent directory.
19180Sstevel@tonic-gate 		 */
19190Sstevel@tonic-gate 		if (strncmp(filename, "drv/", 4) == 0) {
19200Sstevel@tonic-gate 			no_suffixdir_drv = 1;
19210Sstevel@tonic-gate 		}
19220Sstevel@tonic-gate #endif
19230Sstevel@tonic-gate 	}
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	mp->filename = kobj_alloc(strlen(file->_name) + 1, KM_WAIT);
19260Sstevel@tonic-gate 	(void) strcpy(mp->filename, file->_name);
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	if (kobj_read_file(file, (char *)&mp->hdr, sizeof (mp->hdr), 0) < 0) {
19290Sstevel@tonic-gate 		_kobj_printf(ops, "kobj_load_module: %s read header failed\n",
19300Sstevel@tonic-gate 		    modname);
19310Sstevel@tonic-gate 		kobj_free(mp->filename, strlen(file->_name) + 1);
19320Sstevel@tonic-gate 		kobj_free(mp, sizeof (*mp));
19330Sstevel@tonic-gate 		goto bad;
19340Sstevel@tonic-gate 	}
19350Sstevel@tonic-gate 	for (i = 0; i < SELFMAG; i++) {
19360Sstevel@tonic-gate 		if (mp->hdr.e_ident[i] != ELFMAG[i]) {
19370Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_ERRMSG)
19380Sstevel@tonic-gate 				_kobj_printf(ops, "%s not an elf module\n",
19390Sstevel@tonic-gate 				    modname);
19400Sstevel@tonic-gate 			kobj_free(mp->filename, strlen(file->_name) + 1);
19410Sstevel@tonic-gate 			kobj_free(mp, sizeof (*mp));
19420Sstevel@tonic-gate 			goto bad;
19430Sstevel@tonic-gate 		}
19440Sstevel@tonic-gate 	}
19450Sstevel@tonic-gate 	/*
19460Sstevel@tonic-gate 	 * It's ELF, but is it our ISA?  Interpreting the header
19470Sstevel@tonic-gate 	 * from a file for a byte-swapped ISA could cause a huge
19480Sstevel@tonic-gate 	 * and unsatisfiable value to be passed to kobj_alloc below
19490Sstevel@tonic-gate 	 * and therefore hang booting.
19500Sstevel@tonic-gate 	 */
19510Sstevel@tonic-gate 	if (!elf_mach_ok(&mp->hdr)) {
19520Sstevel@tonic-gate 		if (_moddebug & MODDEBUG_ERRMSG)
19530Sstevel@tonic-gate 			_kobj_printf(ops, "%s not an elf module for this ISA\n",
19540Sstevel@tonic-gate 			    modname);
19550Sstevel@tonic-gate 		kobj_free(mp->filename, strlen(file->_name) + 1);
19560Sstevel@tonic-gate 		kobj_free(mp, sizeof (*mp));
19570Sstevel@tonic-gate #ifdef MODDIR_SUFFIX
19580Sstevel@tonic-gate 		/*
19590Sstevel@tonic-gate 		 * The driver mod is not in the ISA specific subdirectory
19600Sstevel@tonic-gate 		 * and the module in the parent directory is not our ISA.
19610Sstevel@tonic-gate 		 * If it is our ISA, for now we will silently succeed.
19620Sstevel@tonic-gate 		 */
19630Sstevel@tonic-gate 		if (no_suffixdir_drv == 1) {
19640Sstevel@tonic-gate 			cmn_err(CE_CONT, "?NOTICE: %s: 64-bit driver module"
19650Sstevel@tonic-gate 			    " not found\n", modname);
19660Sstevel@tonic-gate 		}
19670Sstevel@tonic-gate #endif
19680Sstevel@tonic-gate 		goto bad;
19690Sstevel@tonic-gate 	}
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	/*
19720Sstevel@tonic-gate 	 * All modules, save for unix, should be relocatable (as opposed to
19730Sstevel@tonic-gate 	 * dynamic).  Dynamic modules come with PLTs and GOTs, which can't
19740Sstevel@tonic-gate 	 * currently be processed by krtld.
19750Sstevel@tonic-gate 	 */
19760Sstevel@tonic-gate 	if (mp->hdr.e_type != ET_REL) {
19770Sstevel@tonic-gate 		if (_moddebug & MODDEBUG_ERRMSG)
19780Sstevel@tonic-gate 			_kobj_printf(ops, "%s isn't a relocatable (ET_REL) "
19790Sstevel@tonic-gate 			    "module\n", modname);
19800Sstevel@tonic-gate 		kobj_free(mp->filename, strlen(file->_name) + 1);
19810Sstevel@tonic-gate 		kobj_free(mp, sizeof (*mp));
19820Sstevel@tonic-gate 		goto bad;
19830Sstevel@tonic-gate 	}
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 	n = mp->hdr.e_shentsize * mp->hdr.e_shnum;
19860Sstevel@tonic-gate 	mp->shdrs = kobj_alloc(n, KM_WAIT);
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	if (kobj_read_file(file, mp->shdrs, n, mp->hdr.e_shoff) < 0) {
19890Sstevel@tonic-gate 		_kobj_printf(ops, "kobj_load_module: %s error reading "
19900Sstevel@tonic-gate 		    "section headers\n", modname);
19910Sstevel@tonic-gate 		kobj_free(mp->shdrs, n);
19920Sstevel@tonic-gate 		kobj_free(mp->filename, strlen(file->_name) + 1);
19930Sstevel@tonic-gate 		kobj_free(mp, sizeof (*mp));
19940Sstevel@tonic-gate 		goto bad;
19950Sstevel@tonic-gate 	}
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	kobj_notify(KOBJ_NOTIFY_MODLOADING, modp);
19980Sstevel@tonic-gate 	module_assign(modp, mp);
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	/* read in sections */
20010Sstevel@tonic-gate 	if (get_progbits(mp, file) < 0) {
20020Sstevel@tonic-gate 		_kobj_printf(ops, "%s error reading sections\n", modname);
20030Sstevel@tonic-gate 		goto bad;
20040Sstevel@tonic-gate 	}
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate 	if (do_dynamic(mp, file) < 0) {
20070Sstevel@tonic-gate 		_kobj_printf(ops, "%s error reading dynamic section\n",
20080Sstevel@tonic-gate 		    modname);
20090Sstevel@tonic-gate 		goto bad;
20100Sstevel@tonic-gate 	}
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	modp->mod_text = mp->text;
20130Sstevel@tonic-gate 	modp->mod_text_size = mp->text_size;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	/* read in symbols; adjust values for each section's real address */
20160Sstevel@tonic-gate 	if (get_syms(mp, file) < 0) {
20170Sstevel@tonic-gate 		_kobj_printf(ops, "%s error reading symbols\n",
20180Sstevel@tonic-gate 		    modname);
20190Sstevel@tonic-gate 		goto bad;
20200Sstevel@tonic-gate 	}
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	/*
20230Sstevel@tonic-gate 	 * If we didn't dependency information from the dynamic section, look
20240Sstevel@tonic-gate 	 * for it the old-fashioned way.
20250Sstevel@tonic-gate 	 */
20260Sstevel@tonic-gate 	if (mp->depends_on == NULL)
20270Sstevel@tonic-gate 		mp->depends_on = depends_on(mp);
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate 	if (get_ctf(mp, file) < 0) {
20300Sstevel@tonic-gate 		_kobj_printf(ops, "%s debug information will not "
20310Sstevel@tonic-gate 		    "be available\n", modname);
20320Sstevel@tonic-gate 	}
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 	/* primary kernel modules do not have a signature section */
20350Sstevel@tonic-gate 	if (!(mp->flags & KOBJ_PRIM))
20360Sstevel@tonic-gate 		get_signature(mp, file);
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
20390Sstevel@tonic-gate 	if (kobj_debug & D_LOADING) {
20400Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: file=%s\n", mp->filename);
20410Sstevel@tonic-gate 		_kobj_printf(ops, "\ttext:0x%p", mp->text);
20420Sstevel@tonic-gate 		_kobj_printf(ops, " size: 0x%x\n", mp->text_size);
20430Sstevel@tonic-gate 		_kobj_printf(ops, "\tdata:0x%p", mp->data);
20440Sstevel@tonic-gate 		_kobj_printf(ops, " dsize: 0x%x\n", mp->data_size);
20450Sstevel@tonic-gate 	}
20460Sstevel@tonic-gate #endif /* KOBJ_DEBUG */
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	/*
20490Sstevel@tonic-gate 	 * For primary kernel modules, we defer
20500Sstevel@tonic-gate 	 * symbol resolution and relocation until
20510Sstevel@tonic-gate 	 * all primary objects have been loaded.
20520Sstevel@tonic-gate 	 */
20530Sstevel@tonic-gate 	if (!standalone) {
20540Sstevel@tonic-gate 		int ddrval, dcrval;
20550Sstevel@tonic-gate 		char *dependent_modname;
20560Sstevel@tonic-gate 		/* load all dependents */
20570Sstevel@tonic-gate 		dependent_modname = kobj_zalloc(MODMAXNAMELEN, KM_WAIT);
20580Sstevel@tonic-gate 		ddrval = do_dependents(modp, dependent_modname, MODMAXNAMELEN);
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 		/*
20610Sstevel@tonic-gate 		 * resolve undefined and common symbols,
20620Sstevel@tonic-gate 		 * also allocates common space
20630Sstevel@tonic-gate 		 */
20640Sstevel@tonic-gate 		if ((dcrval = do_common(mp)) < 0) {
20650Sstevel@tonic-gate 			switch (dcrval) {
20660Sstevel@tonic-gate 			case DOSYM_UNSAFE:
20670Sstevel@tonic-gate 				_kobj_printf(ops, "WARNING: mod_load: "
20680Sstevel@tonic-gate 				    "MT-unsafe module '%s' rejected\n",
20690Sstevel@tonic-gate 				    modname);
20700Sstevel@tonic-gate 				break;
20710Sstevel@tonic-gate 			case DOSYM_UNDEF:
20720Sstevel@tonic-gate 				_kobj_printf(ops, "WARNING: mod_load: "
20730Sstevel@tonic-gate 				    "cannot load module '%s'\n",
20740Sstevel@tonic-gate 				    modname);
20750Sstevel@tonic-gate 				if (ddrval == -1) {
20760Sstevel@tonic-gate 					_kobj_printf(ops, "WARNING: %s: ",
20770Sstevel@tonic-gate 					    modname);
20780Sstevel@tonic-gate 					_kobj_printf(ops,
20790Sstevel@tonic-gate 					    "unable to resolve dependency, "
20800Sstevel@tonic-gate 					    "module '%s' not found\n",
20810Sstevel@tonic-gate 					    dependent_modname);
20820Sstevel@tonic-gate 				}
20830Sstevel@tonic-gate 				break;
20840Sstevel@tonic-gate 			}
20850Sstevel@tonic-gate 		}
20860Sstevel@tonic-gate 		kobj_free(dependent_modname, MODMAXNAMELEN);
20870Sstevel@tonic-gate 		if (dcrval < 0)
20880Sstevel@tonic-gate 			goto bad;
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		/* process relocation tables */
20910Sstevel@tonic-gate 		if (do_relocations(mp) < 0) {
20920Sstevel@tonic-gate 			_kobj_printf(ops, "%s error doing relocations\n",
20930Sstevel@tonic-gate 			    modname);
20940Sstevel@tonic-gate 			goto bad;
20950Sstevel@tonic-gate 		}
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 		if (mp->destination) {
20980Sstevel@tonic-gate 			off_t	off = (uintptr_t)mp->destination & PAGEOFFSET;
20990Sstevel@tonic-gate 			caddr_t	base = (caddr_t)mp->destination - off;
21000Sstevel@tonic-gate 			size_t	size = P2ROUNDUP(mp->text_size + off, PAGESIZE);
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 			hat_unload(kas.a_hat, base, size, HAT_UNLOAD_UNLOCK);
21030Sstevel@tonic-gate 			vmem_free(heap_arena, base, size);
21040Sstevel@tonic-gate 		}
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 		/* sync_instruction_memory */
21070Sstevel@tonic-gate 		kobj_sync_instruction_memory(mp->text, mp->text_size);
21080Sstevel@tonic-gate #ifdef	MPSAS
21090Sstevel@tonic-gate 		sas_syms(mp);
21100Sstevel@tonic-gate #endif
21110Sstevel@tonic-gate 		kobj_export_module(mp);
21120Sstevel@tonic-gate 		kobj_notify(KOBJ_NOTIFY_MODLOADED, modp);
21130Sstevel@tonic-gate 	}
21140Sstevel@tonic-gate 	kobj_close_file(file);
21150Sstevel@tonic-gate 	return (0);
21160Sstevel@tonic-gate bad:
21170Sstevel@tonic-gate 	if (file != (struct _buf *)-1)
21180Sstevel@tonic-gate 		kobj_close_file(file);
21190Sstevel@tonic-gate 	if (modp->mod_mp != NULL)
21200Sstevel@tonic-gate 		free_module_data(modp->mod_mp);
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	module_assign(modp, NULL);
21230Sstevel@tonic-gate 	return ((file == (struct _buf *)-1) ? ENOENT : EINVAL);
21240Sstevel@tonic-gate }
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate int
21270Sstevel@tonic-gate kobj_load_primary_module(struct modctl *modp)
21280Sstevel@tonic-gate {
21290Sstevel@tonic-gate 	struct modctl *dep;
21300Sstevel@tonic-gate 	struct module *mp;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 	if (kobj_load_module(modp, 0) != 0)
21330Sstevel@tonic-gate 		return (-1);
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	mp = modp->mod_mp;
21360Sstevel@tonic-gate 	mp->flags |= KOBJ_PRIM;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 	/* Bind new module to its dependents */
21390Sstevel@tonic-gate 	if (mp->depends_on != NULL && (dep =
21400Sstevel@tonic-gate 	    mod_already_loaded(mp->depends_on)) == NULL) {
21410Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
21420Sstevel@tonic-gate 		if (kobj_debug & D_DEBUG) {
21430Sstevel@tonic-gate 			_kobj_printf(ops, "krtld: failed to resolve deps "
21440Sstevel@tonic-gate 			    "for primary %s\n", modp->mod_modname);
21450Sstevel@tonic-gate 		}
21460Sstevel@tonic-gate #endif
21470Sstevel@tonic-gate 		return (-1);
21480Sstevel@tonic-gate 	}
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	add_dependent(mp, dep->mod_mp);
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	/*
21530Sstevel@tonic-gate 	 * Relocate it.  This module may not be part of a link map, so we
21540Sstevel@tonic-gate 	 * can't use bind_primary.
21550Sstevel@tonic-gate 	 */
21560Sstevel@tonic-gate 	if (do_common(mp) < 0 || do_symbols(mp, 0) < 0 ||
21570Sstevel@tonic-gate 	    do_relocations(mp) < 0) {
21580Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
21590Sstevel@tonic-gate 		if (kobj_debug & D_DEBUG) {
21600Sstevel@tonic-gate 			_kobj_printf(ops, "krtld: failed to relocate "
21610Sstevel@tonic-gate 			    "primary %s\n", modp->mod_modname);
21620Sstevel@tonic-gate 		}
21630Sstevel@tonic-gate #endif
21640Sstevel@tonic-gate 		return (-1);
21650Sstevel@tonic-gate 	}
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	return (0);
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate static void
21710Sstevel@tonic-gate module_assign(struct modctl *cp, struct module *mp)
21720Sstevel@tonic-gate {
21730Sstevel@tonic-gate 	if (standalone) {
21740Sstevel@tonic-gate 		cp->mod_mp = mp;
21750Sstevel@tonic-gate 		return;
21760Sstevel@tonic-gate 	}
21770Sstevel@tonic-gate 	mutex_enter(&mod_lock);
21780Sstevel@tonic-gate 	cp->mod_mp = mp;
21790Sstevel@tonic-gate 	cp->mod_gencount++;
21800Sstevel@tonic-gate 	mutex_exit(&mod_lock);
21810Sstevel@tonic-gate }
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate void
21840Sstevel@tonic-gate kobj_unload_module(struct modctl *modp)
21850Sstevel@tonic-gate {
21860Sstevel@tonic-gate 	struct module *mp = modp->mod_mp;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	if ((_moddebug & MODDEBUG_KEEPTEXT) && mp) {
21890Sstevel@tonic-gate 		_kobj_printf(ops, "text for %s ", mp->filename);
21900Sstevel@tonic-gate 		_kobj_printf(ops, "was at %p\n", mp->text);
21910Sstevel@tonic-gate 		mp->text = NULL;	/* don't actually free it */
21920Sstevel@tonic-gate 	}
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	kobj_notify(KOBJ_NOTIFY_MODUNLOADING, modp);
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate 	/*
21970Sstevel@tonic-gate 	 * Null out mod_mp first, so consumers (debuggers) know not to look
21980Sstevel@tonic-gate 	 * at the module structure any more.
21990Sstevel@tonic-gate 	 */
22000Sstevel@tonic-gate 	mutex_enter(&mod_lock);
22010Sstevel@tonic-gate 	modp->mod_mp = NULL;
22020Sstevel@tonic-gate 	mutex_exit(&mod_lock);
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	kobj_notify(KOBJ_NOTIFY_MODUNLOADED, modp);
22050Sstevel@tonic-gate 	free_module_data(mp);
22060Sstevel@tonic-gate }
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate static void
22090Sstevel@tonic-gate free_module_data(struct module *mp)
22100Sstevel@tonic-gate {
22110Sstevel@tonic-gate 	struct module_list *lp, *tmp;
22120Sstevel@tonic-gate 	int ksyms_exported = 0;
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate 	lp = mp->head;
22150Sstevel@tonic-gate 	while (lp) {
22160Sstevel@tonic-gate 		tmp = lp;
22170Sstevel@tonic-gate 		lp = lp->next;
22180Sstevel@tonic-gate 		kobj_free((char *)tmp, sizeof (*tmp));
22190Sstevel@tonic-gate 	}
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	rw_enter(&ksyms_lock, RW_WRITER);
22220Sstevel@tonic-gate 	if (mp->symspace) {
22230Sstevel@tonic-gate 		if (vmem_contains(ksyms_arena, mp->symspace, mp->symsize)) {
22240Sstevel@tonic-gate 			vmem_free(ksyms_arena, mp->symspace, mp->symsize);
22250Sstevel@tonic-gate 			ksyms_exported = 1;
22260Sstevel@tonic-gate 		} else {
22270Sstevel@tonic-gate 			if (mp->flags & KOBJ_NOKSYMS)
22280Sstevel@tonic-gate 				ksyms_exported = 1;
22290Sstevel@tonic-gate 			kobj_free(mp->symspace, mp->symsize);
22300Sstevel@tonic-gate 		}
22310Sstevel@tonic-gate 	}
22320Sstevel@tonic-gate 	rw_exit(&ksyms_lock);
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	if (mp->ctfdata) {
22350Sstevel@tonic-gate 		if (vmem_contains(ctf_arena, mp->ctfdata, mp->ctfsize))
22360Sstevel@tonic-gate 			vmem_free(ctf_arena, mp->ctfdata, mp->ctfsize);
22370Sstevel@tonic-gate 		else
22380Sstevel@tonic-gate 			kobj_free(mp->ctfdata, mp->ctfsize);
22390Sstevel@tonic-gate 	}
22400Sstevel@tonic-gate 
22410Sstevel@tonic-gate 	if (mp->sigdata)
22420Sstevel@tonic-gate 		kobj_free(mp->sigdata, mp->sigsize);
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	/*
22450Sstevel@tonic-gate 	 * We did not get far enough into kobj_export_ksyms() to free allocated
22460Sstevel@tonic-gate 	 * buffers because we encounted error conditions. Free the buffers.
22470Sstevel@tonic-gate 	 */
22480Sstevel@tonic-gate 	if ((ksyms_exported == 0) && (mp->shdrs != NULL)) {
22490Sstevel@tonic-gate 		uint_t shn;
22500Sstevel@tonic-gate 		Shdr *shp;
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 		for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
22530Sstevel@tonic-gate 			shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
22540Sstevel@tonic-gate 			switch (shp->sh_type) {
22550Sstevel@tonic-gate 			case SHT_RELA:
22560Sstevel@tonic-gate 			case SHT_REL:
22570Sstevel@tonic-gate 				if (shp->sh_addr != 0)
22580Sstevel@tonic-gate 					kobj_free((void *)shp->sh_addr,
22590Sstevel@tonic-gate 					    shp->sh_size);
22600Sstevel@tonic-gate 				break;
22610Sstevel@tonic-gate 			}
22620Sstevel@tonic-gate 		}
22630Sstevel@tonic-gate err_free_done:
22640Sstevel@tonic-gate 		if (!(mp->flags & KOBJ_PRIM)) {
22650Sstevel@tonic-gate 			kobj_free(mp->shdrs,
22660Sstevel@tonic-gate 			    mp->hdr.e_shentsize * mp->hdr.e_shnum);
22670Sstevel@tonic-gate 		}
22680Sstevel@tonic-gate 	}
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	if (mp->bss)
22710Sstevel@tonic-gate 		vmem_free(data_arena, (void *)mp->bss, mp->bss_size);
22720Sstevel@tonic-gate 
22730Sstevel@tonic-gate 	if (mp->fbt_tab)
22740Sstevel@tonic-gate 		kobj_texthole_free(mp->fbt_tab, mp->fbt_size);
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	if (mp->textwin_base)
22770Sstevel@tonic-gate 		kobj_textwin_free(mp);
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	if (mp->sdt_probes != NULL) {
22800Sstevel@tonic-gate 		sdt_probedesc_t *sdp = mp->sdt_probes, *next;
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 		while (sdp != NULL) {
22830Sstevel@tonic-gate 			next = sdp->sdpd_next;
22840Sstevel@tonic-gate 			kobj_free(sdp->sdpd_name, strlen(sdp->sdpd_name) + 1);
22850Sstevel@tonic-gate 			kobj_free(sdp, sizeof (sdt_probedesc_t));
22860Sstevel@tonic-gate 			sdp = next;
22870Sstevel@tonic-gate 		}
22880Sstevel@tonic-gate 	}
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate 	if (mp->sdt_tab)
22910Sstevel@tonic-gate 		kobj_texthole_free(mp->sdt_tab, mp->sdt_size);
22920Sstevel@tonic-gate 	if (mp->text)
22930Sstevel@tonic-gate 		vmem_free(text_arena, mp->text, mp->text_size);
22940Sstevel@tonic-gate 	if (mp->data)
22950Sstevel@tonic-gate 		vmem_free(data_arena, mp->data, mp->data_size);
22960Sstevel@tonic-gate 	if (mp->depends_on)
22970Sstevel@tonic-gate 		kobj_free(mp->depends_on, strlen(mp->depends_on)+1);
22980Sstevel@tonic-gate 	if (mp->filename)
22990Sstevel@tonic-gate 		kobj_free(mp->filename, strlen(mp->filename)+1);
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	kobj_free((char *)mp, sizeof (*mp));
23020Sstevel@tonic-gate }
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate static int
23050Sstevel@tonic-gate get_progbits(struct module *mp, struct _buf *file)
23060Sstevel@tonic-gate {
23070Sstevel@tonic-gate 	struct proginfo *tp, *dp, *sdp;
23080Sstevel@tonic-gate 	Shdr *shp;
23090Sstevel@tonic-gate 	reloc_dest_t dest = NULL;
23100Sstevel@tonic-gate 	uintptr_t bits_ptr;
23110Sstevel@tonic-gate 	uintptr_t text = 0, data, sdata = 0, textptr;
23120Sstevel@tonic-gate 	uint_t shn;
23130Sstevel@tonic-gate 	int err = -1;
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	tp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT);
23160Sstevel@tonic-gate 	dp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT);
23170Sstevel@tonic-gate 	sdp = kobj_zalloc(sizeof (struct proginfo), KM_WAIT);
23180Sstevel@tonic-gate 	/*
23190Sstevel@tonic-gate 	 * loop through sections to find out how much space we need
23200Sstevel@tonic-gate 	 * for text, data, (also bss that is already assigned)
23210Sstevel@tonic-gate 	 */
23220Sstevel@tonic-gate 	if (get_progbits_size(mp, tp, dp, sdp) < 0)
23230Sstevel@tonic-gate 		goto done;
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	mp->text_size = tp->size;
23260Sstevel@tonic-gate 	mp->data_size = dp->size;
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	if (standalone) {
23293446Smrj 		caddr_t limit = _data;
23303446Smrj 
23313446Smrj 		if (lg_pagesize && _text + lg_pagesize < limit)
23323446Smrj 			limit = _text + lg_pagesize;
23333446Smrj 
23340Sstevel@tonic-gate 		mp->text = kobj_segbrk(&_etext, mp->text_size,
23353912Slling 		    tp->align, limit);
23360Sstevel@tonic-gate 		/*
23370Sstevel@tonic-gate 		 * If we can't grow the text segment, try the
23380Sstevel@tonic-gate 		 * data segment before failing.
23390Sstevel@tonic-gate 		 */
23400Sstevel@tonic-gate 		if (mp->text == NULL) {
23410Sstevel@tonic-gate 			mp->text = kobj_segbrk(&_edata, mp->text_size,
23423912Slling 			    tp->align, 0);
23430Sstevel@tonic-gate 		}
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 		mp->data = kobj_segbrk(&_edata, mp->data_size, dp->align, 0);
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 		if (mp->text == NULL || mp->data == NULL)
23480Sstevel@tonic-gate 			goto done;
23490Sstevel@tonic-gate 
23500Sstevel@tonic-gate 	} else {
23510Sstevel@tonic-gate 		if (text_arena == NULL)
23520Sstevel@tonic-gate 			kobj_vmem_init(&text_arena, &data_arena);
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 		/*
23550Sstevel@tonic-gate 		 * some architectures may want to load the module on a
23560Sstevel@tonic-gate 		 * page that is currently read only. It may not be
23570Sstevel@tonic-gate 		 * possible for those architectures to remap their page
23580Sstevel@tonic-gate 		 * on the fly. So we provide a facility for them to hang
23590Sstevel@tonic-gate 		 * a private hook where the memory they assign the module
23600Sstevel@tonic-gate 		 * is not the actual place where the module loads.
23610Sstevel@tonic-gate 		 *
23620Sstevel@tonic-gate 		 * In this case there are two addresses that deal with the
23630Sstevel@tonic-gate 		 * modload.
23640Sstevel@tonic-gate 		 * 1) the final destination of the module
23650Sstevel@tonic-gate 		 * 2) the address that is used to view the newly
23660Sstevel@tonic-gate 		 * loaded module until all the relocations relative to 1
23670Sstevel@tonic-gate 		 * above are completed.
23680Sstevel@tonic-gate 		 *
23690Sstevel@tonic-gate 		 * That is what dest is used for below.
23700Sstevel@tonic-gate 		 */
23710Sstevel@tonic-gate 		mp->text_size += tp->align;
23720Sstevel@tonic-gate 		mp->data_size += dp->align;
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate 		mp->text = kobj_text_alloc(text_arena, mp->text_size);
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 		/*
23770Sstevel@tonic-gate 		 * a remap is taking place. Align the text ptr relative
23780Sstevel@tonic-gate 		 * to the secondary mapping. That is where the bits will
23790Sstevel@tonic-gate 		 * be read in.
23800Sstevel@tonic-gate 		 */
23810Sstevel@tonic-gate 		if (kvseg.s_base != NULL && !vmem_contains(heaptext_arena,
23820Sstevel@tonic-gate 		    mp->text, mp->text_size)) {
23830Sstevel@tonic-gate 			off_t	off = (uintptr_t)mp->text & PAGEOFFSET;
23840Sstevel@tonic-gate 			size_t	size = P2ROUNDUP(mp->text_size + off, PAGESIZE);
23850Sstevel@tonic-gate 			caddr_t	map = vmem_alloc(heap_arena, size, VM_SLEEP);
23860Sstevel@tonic-gate 			caddr_t orig = mp->text - off;
23870Sstevel@tonic-gate 			pgcnt_t pages = size / PAGESIZE;
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 			dest = (reloc_dest_t)(map + off);
23900Sstevel@tonic-gate 			text = ALIGN((uintptr_t)dest, tp->align);
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 			while (pages--) {
23930Sstevel@tonic-gate 				hat_devload(kas.a_hat, map, PAGESIZE,
23940Sstevel@tonic-gate 				    hat_getpfnum(kas.a_hat, orig),
23950Sstevel@tonic-gate 				    PROT_READ | PROT_WRITE | PROT_EXEC,
23960Sstevel@tonic-gate 				    HAT_LOAD_NOCONSIST | HAT_LOAD_LOCK);
23970Sstevel@tonic-gate 				map += PAGESIZE;
23980Sstevel@tonic-gate 				orig += PAGESIZE;
23990Sstevel@tonic-gate 			}
24000Sstevel@tonic-gate 			/*
24010Sstevel@tonic-gate 			 * Since we set up a non-cacheable mapping, we need
24020Sstevel@tonic-gate 			 * to flush any old entries in the cache that might
24030Sstevel@tonic-gate 			 * be left around from the read-only mapping.
24040Sstevel@tonic-gate 			 */
24050Sstevel@tonic-gate 			dcache_flushall();
24060Sstevel@tonic-gate 		}
24070Sstevel@tonic-gate 		if (mp->data_size)
24080Sstevel@tonic-gate 			mp->data = vmem_alloc(data_arena, mp->data_size,
24090Sstevel@tonic-gate 			    VM_SLEEP | VM_BESTFIT);
24100Sstevel@tonic-gate 	}
24110Sstevel@tonic-gate 	textptr = (uintptr_t)mp->text;
24120Sstevel@tonic-gate 	textptr = ALIGN(textptr, tp->align);
24130Sstevel@tonic-gate 	mp->destination = dest;
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate 	/*
24160Sstevel@tonic-gate 	 * This is the case where a remap is not being done.
24170Sstevel@tonic-gate 	 */
24180Sstevel@tonic-gate 	if (text == 0)
24190Sstevel@tonic-gate 		text = ALIGN((uintptr_t)mp->text, tp->align);
24200Sstevel@tonic-gate 	data = ALIGN((uintptr_t)mp->data, dp->align);
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	/* now loop though sections assigning addresses and loading the data */
24230Sstevel@tonic-gate 	for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
24240Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
24250Sstevel@tonic-gate 		if (!(shp->sh_flags & SHF_ALLOC))
24260Sstevel@tonic-gate 			continue;
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 		if ((shp->sh_flags & SHF_WRITE) == 0)
24290Sstevel@tonic-gate 			bits_ptr = text;
24300Sstevel@tonic-gate 		else if (shp->sh_flags & SHF_NEUT_SHORT)
24310Sstevel@tonic-gate 			bits_ptr = sdata;
24320Sstevel@tonic-gate 		else
24330Sstevel@tonic-gate 			bits_ptr = data;
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate 		bits_ptr = ALIGN(bits_ptr, shp->sh_addralign);
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 		if (shp->sh_type == SHT_NOBITS) {
24380Sstevel@tonic-gate 			/*
24390Sstevel@tonic-gate 			 * Zero bss.
24400Sstevel@tonic-gate 			 */
24410Sstevel@tonic-gate 			bzero((caddr_t)bits_ptr, shp->sh_size);
24420Sstevel@tonic-gate 			shp->sh_type = SHT_PROGBITS;
24430Sstevel@tonic-gate 		} else {
24440Sstevel@tonic-gate 			if (kobj_read_file(file, (char *)bits_ptr,
24450Sstevel@tonic-gate 			    shp->sh_size, shp->sh_offset) < 0)
24460Sstevel@tonic-gate 				goto done;
24470Sstevel@tonic-gate 		}
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 		if (shp->sh_flags & SHF_WRITE) {
24500Sstevel@tonic-gate 			shp->sh_addr = bits_ptr;
24510Sstevel@tonic-gate 		} else {
24520Sstevel@tonic-gate 			textptr = ALIGN(textptr, shp->sh_addralign);
24530Sstevel@tonic-gate 			shp->sh_addr = textptr;
24540Sstevel@tonic-gate 			textptr += shp->sh_size;
24550Sstevel@tonic-gate 		}
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 		bits_ptr += shp->sh_size;
24580Sstevel@tonic-gate 		if ((shp->sh_flags & SHF_WRITE) == 0)
24590Sstevel@tonic-gate 			text = bits_ptr;
24600Sstevel@tonic-gate 		else if (shp->sh_flags & SHF_NEUT_SHORT)
24610Sstevel@tonic-gate 			sdata = bits_ptr;
24620Sstevel@tonic-gate 		else
24630Sstevel@tonic-gate 			data = bits_ptr;
24640Sstevel@tonic-gate 	}
24650Sstevel@tonic-gate 
24660Sstevel@tonic-gate 	err = 0;
24670Sstevel@tonic-gate done:
24680Sstevel@tonic-gate 	/*
24690Sstevel@tonic-gate 	 * Free and mark as freed the section headers here so that
24700Sstevel@tonic-gate 	 * free_module_data() does not have to worry about this buffer.
24710Sstevel@tonic-gate 	 *
24720Sstevel@tonic-gate 	 * This buffer is freed here because one of the possible reasons
24730Sstevel@tonic-gate 	 * for error is a section with non-zero sh_addr and in that case
24740Sstevel@tonic-gate 	 * free_module_data() would have no way of recognizing that this
24750Sstevel@tonic-gate 	 * buffer was unallocated.
24760Sstevel@tonic-gate 	 */
24770Sstevel@tonic-gate 	if (err != 0) {
24780Sstevel@tonic-gate 		kobj_free(mp->shdrs, mp->hdr.e_shentsize * mp->hdr.e_shnum);
24790Sstevel@tonic-gate 		mp->shdrs = NULL;
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	(void) kobj_free(tp, sizeof (struct proginfo));
24830Sstevel@tonic-gate 	(void) kobj_free(dp, sizeof (struct proginfo));
24840Sstevel@tonic-gate 	(void) kobj_free(sdp, sizeof (struct proginfo));
24850Sstevel@tonic-gate 
24860Sstevel@tonic-gate 	return (err);
24870Sstevel@tonic-gate }
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate /*
24900Sstevel@tonic-gate  * Go through suppress_sym_list to see if "multiply defined"
24910Sstevel@tonic-gate  * warning of this symbol should be suppressed.  Return 1 if
24920Sstevel@tonic-gate  * warning should be suppressed, 0 otherwise.
24930Sstevel@tonic-gate  */
24940Sstevel@tonic-gate static int
24950Sstevel@tonic-gate kobj_suppress_warning(char *symname)
24960Sstevel@tonic-gate {
24970Sstevel@tonic-gate 	int	i;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	for (i = 0; suppress_sym_list[i] != NULL; i++) {
25000Sstevel@tonic-gate 		if (strcmp(suppress_sym_list[i], symname) == 0)
25010Sstevel@tonic-gate 			return (1);
25020Sstevel@tonic-gate 	}
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	return (0);
25050Sstevel@tonic-gate }
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate static int
25080Sstevel@tonic-gate get_syms(struct module *mp, struct _buf *file)
25090Sstevel@tonic-gate {
25100Sstevel@tonic-gate 	uint_t		shn;
25110Sstevel@tonic-gate 	Shdr	*shp;
25120Sstevel@tonic-gate 	uint_t		i;
25130Sstevel@tonic-gate 	Sym	*sp, *ksp;
25140Sstevel@tonic-gate 	char		*symname;
25150Sstevel@tonic-gate 	int		dosymtab = 0;
25160Sstevel@tonic-gate 	extern char 	stubs_base[], stubs_end[];
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 	/*
25190Sstevel@tonic-gate 	 * Find the interesting sections.
25200Sstevel@tonic-gate 	 */
25210Sstevel@tonic-gate 	for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
25220Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
25230Sstevel@tonic-gate 		switch (shp->sh_type) {
25240Sstevel@tonic-gate 		case SHT_SYMTAB:
25250Sstevel@tonic-gate 			mp->symtbl_section = shn;
25260Sstevel@tonic-gate 			mp->symhdr = shp;
25270Sstevel@tonic-gate 			dosymtab++;
25280Sstevel@tonic-gate 			break;
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 		case SHT_RELA:
25310Sstevel@tonic-gate 		case SHT_REL:
25320Sstevel@tonic-gate 			/*
25330Sstevel@tonic-gate 			 * Already loaded.
25340Sstevel@tonic-gate 			 */
25350Sstevel@tonic-gate 			if (shp->sh_addr)
25360Sstevel@tonic-gate 				continue;
25370Sstevel@tonic-gate 			shp->sh_addr = (Addr)
25380Sstevel@tonic-gate 			    kobj_alloc(shp->sh_size, KM_WAIT|KM_TMP);
25390Sstevel@tonic-gate 
25400Sstevel@tonic-gate 			if (kobj_read_file(file, (char *)shp->sh_addr,
25410Sstevel@tonic-gate 			    shp->sh_size, shp->sh_offset) < 0) {
25420Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: get_syms: %s, ",
25430Sstevel@tonic-gate 				    mp->filename);
25440Sstevel@tonic-gate 				_kobj_printf(ops, "error reading section %d\n",
25450Sstevel@tonic-gate 				    shn);
25460Sstevel@tonic-gate 				return (-1);
25470Sstevel@tonic-gate 			}
25480Sstevel@tonic-gate 			break;
25490Sstevel@tonic-gate 		}
25500Sstevel@tonic-gate 	}
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 	/*
25530Sstevel@tonic-gate 	 * This is true for a stripped executable.  In the case of
25540Sstevel@tonic-gate 	 * 'unix' it can be stripped but it still contains the SHT_DYNSYM,
25550Sstevel@tonic-gate 	 * and since that symbol information is still present everything
25560Sstevel@tonic-gate 	 * is just fine.
25570Sstevel@tonic-gate 	 */
25580Sstevel@tonic-gate 	if (!dosymtab) {
25590Sstevel@tonic-gate 		if (mp->flags & KOBJ_EXEC)
25600Sstevel@tonic-gate 			return (0);
25610Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_syms: %s ",
25623912Slling 		    mp->filename);
25630Sstevel@tonic-gate 		_kobj_printf(ops, "no SHT_SYMTAB symbol table found\n");
25640Sstevel@tonic-gate 		return (-1);
25650Sstevel@tonic-gate 	}
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 	/*
25680Sstevel@tonic-gate 	 * get the associated string table header
25690Sstevel@tonic-gate 	 */
25700Sstevel@tonic-gate 	if ((mp->symhdr == 0) || (mp->symhdr->sh_link >= mp->hdr.e_shnum))
25710Sstevel@tonic-gate 		return (-1);
25720Sstevel@tonic-gate 	mp->strhdr = (Shdr *)
25733912Slling 	    (mp->shdrs + mp->symhdr->sh_link * mp->hdr.e_shentsize);
25740Sstevel@tonic-gate 
25750Sstevel@tonic-gate 	mp->nsyms = mp->symhdr->sh_size / mp->symhdr->sh_entsize;
25760Sstevel@tonic-gate 	mp->hashsize = kobj_gethashsize(mp->nsyms);
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 	/*
25790Sstevel@tonic-gate 	 * Allocate space for the symbol table, buckets, chains, and strings.
25800Sstevel@tonic-gate 	 */
25810Sstevel@tonic-gate 	mp->symsize = mp->symhdr->sh_size +
25820Sstevel@tonic-gate 	    (mp->hashsize + mp->nsyms) * sizeof (symid_t) + mp->strhdr->sh_size;
25830Sstevel@tonic-gate 	mp->symspace = kobj_zalloc(mp->symsize, KM_WAIT|KM_SCRATCH);
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 	mp->symtbl = mp->symspace;
25860Sstevel@tonic-gate 	mp->buckets = (symid_t *)(mp->symtbl + mp->symhdr->sh_size);
25870Sstevel@tonic-gate 	mp->chains = mp->buckets + mp->hashsize;
25880Sstevel@tonic-gate 	mp->strings = (char *)(mp->chains + mp->nsyms);
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	if (kobj_read_file(file, mp->symtbl,
25910Sstevel@tonic-gate 	    mp->symhdr->sh_size, mp->symhdr->sh_offset) < 0 ||
25920Sstevel@tonic-gate 	    kobj_read_file(file, mp->strings,
25930Sstevel@tonic-gate 	    mp->strhdr->sh_size, mp->strhdr->sh_offset) < 0)
25940Sstevel@tonic-gate 		return (-1);
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 	/*
25970Sstevel@tonic-gate 	 * loop through the symbol table adjusting values to account
25980Sstevel@tonic-gate 	 * for where each section got loaded into memory.  Also
25990Sstevel@tonic-gate 	 * fill in the hash table.
26000Sstevel@tonic-gate 	 */
26010Sstevel@tonic-gate 	for (i = 1; i < mp->nsyms; i++) {
26020Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + i * mp->symhdr->sh_entsize);
26030Sstevel@tonic-gate 		if (sp->st_shndx < SHN_LORESERVE) {
26040Sstevel@tonic-gate 			if (sp->st_shndx >= mp->hdr.e_shnum) {
26050Sstevel@tonic-gate 				_kobj_printf(ops, "%s bad shndx ",
26060Sstevel@tonic-gate 				    file->_name);
26070Sstevel@tonic-gate 				_kobj_printf(ops, "in symbol %d\n", i);
26080Sstevel@tonic-gate 				return (-1);
26090Sstevel@tonic-gate 			}
26100Sstevel@tonic-gate 			shp = (Shdr *)
26110Sstevel@tonic-gate 			    (mp->shdrs +
26120Sstevel@tonic-gate 			    sp->st_shndx * mp->hdr.e_shentsize);
26130Sstevel@tonic-gate 			if (!(mp->flags & KOBJ_EXEC))
26140Sstevel@tonic-gate 				sp->st_value += shp->sh_addr;
26150Sstevel@tonic-gate 		}
26160Sstevel@tonic-gate 
26170Sstevel@tonic-gate 		if (sp->st_name == 0 || sp->st_shndx == SHN_UNDEF)
26180Sstevel@tonic-gate 			continue;
26190Sstevel@tonic-gate 		if (sp->st_name >= mp->strhdr->sh_size)
26200Sstevel@tonic-gate 			return (-1);
26210Sstevel@tonic-gate 
26220Sstevel@tonic-gate 		symname = mp->strings + sp->st_name;
26230Sstevel@tonic-gate 
26240Sstevel@tonic-gate 		if (!(mp->flags & KOBJ_EXEC) &&
26250Sstevel@tonic-gate 		    ELF_ST_BIND(sp->st_info) == STB_GLOBAL) {
26260Sstevel@tonic-gate 			ksp = kobj_lookup_all(mp, symname, 0);
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 			if (ksp && ELF_ST_BIND(ksp->st_info) == STB_GLOBAL &&
26290Sstevel@tonic-gate 			    !kobj_suppress_warning(symname) &&
26300Sstevel@tonic-gate 			    sp->st_shndx != SHN_UNDEF &&
26310Sstevel@tonic-gate 			    sp->st_shndx != SHN_COMMON &&
26320Sstevel@tonic-gate 			    ksp->st_shndx != SHN_UNDEF &&
26330Sstevel@tonic-gate 			    ksp->st_shndx != SHN_COMMON) {
26340Sstevel@tonic-gate 				/*
26350Sstevel@tonic-gate 				 * Unless this symbol is a stub, it's multiply
26360Sstevel@tonic-gate 				 * defined.  Multiply-defined symbols are
26370Sstevel@tonic-gate 				 * usually bad, but some objects (kmdb) have
26380Sstevel@tonic-gate 				 * a legitimate need to have their own
26390Sstevel@tonic-gate 				 * copies of common functions.
26400Sstevel@tonic-gate 				 */
26410Sstevel@tonic-gate 				if ((standalone ||
26420Sstevel@tonic-gate 				    ksp->st_value < (uintptr_t)stubs_base ||
26430Sstevel@tonic-gate 				    ksp->st_value >= (uintptr_t)stubs_end) &&
26440Sstevel@tonic-gate 				    !(mp->flags & KOBJ_IGNMULDEF)) {
26450Sstevel@tonic-gate 					_kobj_printf(ops,
26460Sstevel@tonic-gate 					    "%s symbol ", file->_name);
26470Sstevel@tonic-gate 					_kobj_printf(ops,
26480Sstevel@tonic-gate 					    "%s multiply defined\n", symname);
26490Sstevel@tonic-gate 				}
26500Sstevel@tonic-gate 			}
26510Sstevel@tonic-gate 		}
26523446Smrj 
26530Sstevel@tonic-gate 		sym_insert(mp, symname, i);
26540Sstevel@tonic-gate 	}
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	return (0);
26570Sstevel@tonic-gate }
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate static int
26600Sstevel@tonic-gate get_ctf(struct module *mp, struct _buf *file)
26610Sstevel@tonic-gate {
26620Sstevel@tonic-gate 	char *shstrtab, *ctfdata;
26630Sstevel@tonic-gate 	size_t shstrlen;
26640Sstevel@tonic-gate 	Shdr *shp;
26650Sstevel@tonic-gate 	uint_t i;
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	if (_moddebug & MODDEBUG_NOCTF)
26680Sstevel@tonic-gate 		return (0); /* do not attempt to even load CTF data */
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate 	if (mp->hdr.e_shstrndx >= mp->hdr.e_shnum) {
26710Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_ctf: %s, ",
26720Sstevel@tonic-gate 		    mp->filename);
26730Sstevel@tonic-gate 		_kobj_printf(ops, "corrupt e_shstrndx %u\n",
26740Sstevel@tonic-gate 		    mp->hdr.e_shstrndx);
26750Sstevel@tonic-gate 		return (-1);
26760Sstevel@tonic-gate 	}
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
26790Sstevel@tonic-gate 	shstrlen = shp->sh_size;
26800Sstevel@tonic-gate 	shstrtab = kobj_alloc(shstrlen, KM_WAIT|KM_TMP);
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate 	if (kobj_read_file(file, shstrtab, shstrlen, shp->sh_offset) < 0) {
26830Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_ctf: %s, ",
26840Sstevel@tonic-gate 		    mp->filename);
26850Sstevel@tonic-gate 		_kobj_printf(ops, "error reading section %u\n",
26860Sstevel@tonic-gate 		    mp->hdr.e_shstrndx);
26870Sstevel@tonic-gate 		kobj_free(shstrtab, shstrlen);
26880Sstevel@tonic-gate 		return (-1);
26890Sstevel@tonic-gate 	}
26900Sstevel@tonic-gate 
26910Sstevel@tonic-gate 	for (i = 0; i < mp->hdr.e_shnum; i++) {
26920Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + i * mp->hdr.e_shentsize);
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 		if (shp->sh_size != 0 && shp->sh_name < shstrlen &&
26950Sstevel@tonic-gate 		    strcmp(shstrtab + shp->sh_name, ".SUNW_ctf") == 0) {
26960Sstevel@tonic-gate 			ctfdata = kobj_alloc(shp->sh_size, KM_WAIT|KM_SCRATCH);
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate 			if (kobj_read_file(file, ctfdata, shp->sh_size,
26990Sstevel@tonic-gate 			    shp->sh_offset) < 0) {
27000Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: get_ctf: %s, error "
27010Sstevel@tonic-gate 				    "reading .SUNW_ctf data\n", mp->filename);
27020Sstevel@tonic-gate 				kobj_free(ctfdata, shp->sh_size);
27030Sstevel@tonic-gate 				kobj_free(shstrtab, shstrlen);
27040Sstevel@tonic-gate 				return (-1);
27050Sstevel@tonic-gate 			}
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 			mp->ctfdata = ctfdata;
27080Sstevel@tonic-gate 			mp->ctfsize = shp->sh_size;
27090Sstevel@tonic-gate 			break;
27100Sstevel@tonic-gate 		}
27110Sstevel@tonic-gate 	}
27120Sstevel@tonic-gate 
27130Sstevel@tonic-gate 	kobj_free(shstrtab, shstrlen);
27140Sstevel@tonic-gate 	return (0);
27150Sstevel@tonic-gate }
27160Sstevel@tonic-gate 
27170Sstevel@tonic-gate #define	SHA1_DIGEST_LENGTH	20	/* SHA1 digest length in bytes */
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate /*
27200Sstevel@tonic-gate  * Return the hash of the ELF sections that are memory resident.
27210Sstevel@tonic-gate  * i.e. text and data.  We skip a SHT_NOBITS section since it occupies
27220Sstevel@tonic-gate  * no space in the file. We use SHA1 here since libelfsign uses
27230Sstevel@tonic-gate  * it and both places need to use the same algorithm.
27240Sstevel@tonic-gate  */
27250Sstevel@tonic-gate static void
27260Sstevel@tonic-gate crypto_es_hash(struct module *mp, char *hash, char *shstrtab)
27270Sstevel@tonic-gate {
27280Sstevel@tonic-gate 	uint_t shn;
27290Sstevel@tonic-gate 	Shdr *shp;
27300Sstevel@tonic-gate 	SHA1_CTX ctx;
27310Sstevel@tonic-gate 
27320Sstevel@tonic-gate 	SHA1Init(&ctx);
27330Sstevel@tonic-gate 
27340Sstevel@tonic-gate 	for (shn = 1; shn < mp->hdr.e_shnum; shn++) {
27350Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + shn * mp->hdr.e_shentsize);
27360Sstevel@tonic-gate 		if (!(shp->sh_flags & SHF_ALLOC) || shp->sh_size == 0)
27370Sstevel@tonic-gate 			continue;
27380Sstevel@tonic-gate 
27390Sstevel@tonic-gate 		/*
27400Sstevel@tonic-gate 		 * The check should ideally be shp->sh_type == SHT_NOBITS.
27410Sstevel@tonic-gate 		 * However, we can't do that check here as get_progbits()
27420Sstevel@tonic-gate 		 * resets the type.
27430Sstevel@tonic-gate 		 */
27440Sstevel@tonic-gate 		if (strcmp(shstrtab + shp->sh_name, ".bss") == 0)
27450Sstevel@tonic-gate 			continue;
27460Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
27470Sstevel@tonic-gate 		if (kobj_debug & D_DEBUG)
27480Sstevel@tonic-gate 			_kobj_printf(ops,
27490Sstevel@tonic-gate 			    "krtld: crypto_es_hash: updating hash with"
27500Sstevel@tonic-gate 			    " %s data size=%d\n", shstrtab + shp->sh_name,
27513912Slling 			    shp->sh_size);
27520Sstevel@tonic-gate #endif
27530Sstevel@tonic-gate 		ASSERT(shp->sh_addr != NULL);
27540Sstevel@tonic-gate 		SHA1Update(&ctx, (const uint8_t *)shp->sh_addr, shp->sh_size);
27550Sstevel@tonic-gate 	}
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate 	SHA1Final((uchar_t *)hash, &ctx);
27580Sstevel@tonic-gate }
27590Sstevel@tonic-gate 
27600Sstevel@tonic-gate /*
27610Sstevel@tonic-gate  * Get the .SUNW_signature section for the module, it it exists.
27620Sstevel@tonic-gate  *
27630Sstevel@tonic-gate  * This section exists only for crypto modules. None of the
27640Sstevel@tonic-gate  * primary modules have this section currently.
27650Sstevel@tonic-gate  */
27660Sstevel@tonic-gate static void
27670Sstevel@tonic-gate get_signature(struct module *mp, struct _buf *file)
27680Sstevel@tonic-gate {
27690Sstevel@tonic-gate 	char *shstrtab, *sigdata = NULL;
27700Sstevel@tonic-gate 	size_t shstrlen;
27710Sstevel@tonic-gate 	Shdr *shp;
27720Sstevel@tonic-gate 	uint_t i;
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 	if (mp->hdr.e_shstrndx >= mp->hdr.e_shnum) {
27750Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_signature: %s, ",
27760Sstevel@tonic-gate 		    mp->filename);
27770Sstevel@tonic-gate 		_kobj_printf(ops, "corrupt e_shstrndx %u\n",
27780Sstevel@tonic-gate 		    mp->hdr.e_shstrndx);
27790Sstevel@tonic-gate 		return;
27800Sstevel@tonic-gate 	}
27810Sstevel@tonic-gate 
27820Sstevel@tonic-gate 	shp = (Shdr *)(mp->shdrs + mp->hdr.e_shstrndx * mp->hdr.e_shentsize);
27830Sstevel@tonic-gate 	shstrlen = shp->sh_size;
27840Sstevel@tonic-gate 	shstrtab = kobj_alloc(shstrlen, KM_WAIT|KM_TMP);
27850Sstevel@tonic-gate 
27860Sstevel@tonic-gate 	if (kobj_read_file(file, shstrtab, shstrlen, shp->sh_offset) < 0) {
27870Sstevel@tonic-gate 		_kobj_printf(ops, "krtld: get_signature: %s, ",
27880Sstevel@tonic-gate 		    mp->filename);
27890Sstevel@tonic-gate 		_kobj_printf(ops, "error reading section %u\n",
27900Sstevel@tonic-gate 		    mp->hdr.e_shstrndx);
27910Sstevel@tonic-gate 		kobj_free(shstrtab, shstrlen);
27920Sstevel@tonic-gate 		return;
27930Sstevel@tonic-gate 	}
27940Sstevel@tonic-gate 
27950Sstevel@tonic-gate 	for (i = 0; i < mp->hdr.e_shnum; i++) {
27960Sstevel@tonic-gate 		shp = (Shdr *)(mp->shdrs + i * mp->hdr.e_shentsize);
27970Sstevel@tonic-gate 		if (shp->sh_size != 0 && shp->sh_name < shstrlen &&
27980Sstevel@tonic-gate 		    strcmp(shstrtab + shp->sh_name,
27990Sstevel@tonic-gate 		    ELF_SIGNATURE_SECTION) == 0) {
28000Sstevel@tonic-gate 			filesig_vers_t filesig_version;
28010Sstevel@tonic-gate 			size_t sigsize = shp->sh_size + SHA1_DIGEST_LENGTH;
28020Sstevel@tonic-gate 			sigdata = kobj_alloc(sigsize, KM_WAIT|KM_SCRATCH);
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate 			if (kobj_read_file(file, sigdata, shp->sh_size,
28050Sstevel@tonic-gate 			    shp->sh_offset) < 0) {
28060Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: get_signature: %s,"
28070Sstevel@tonic-gate 				    " error reading .SUNW_signature data\n",
28080Sstevel@tonic-gate 				    mp->filename);
28090Sstevel@tonic-gate 				kobj_free(sigdata, sigsize);
28100Sstevel@tonic-gate 				kobj_free(shstrtab, shstrlen);
28110Sstevel@tonic-gate 				return;
28120Sstevel@tonic-gate 			}
28130Sstevel@tonic-gate 			filesig_version = ((struct filesignatures *)sigdata)->
28140Sstevel@tonic-gate 			    filesig_sig.filesig_version;
28150Sstevel@tonic-gate 			if (!(filesig_version == FILESIG_VERSION1 ||
28160Sstevel@tonic-gate 			    filesig_version == FILESIG_VERSION3)) {
28170Sstevel@tonic-gate 				/* skip versions we don't understand */
28180Sstevel@tonic-gate 				kobj_free(sigdata, sigsize);
28190Sstevel@tonic-gate 				kobj_free(shstrtab, shstrlen);
28200Sstevel@tonic-gate 				return;
28210Sstevel@tonic-gate 			}
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 			mp->sigdata = sigdata;
28240Sstevel@tonic-gate 			mp->sigsize = sigsize;
28250Sstevel@tonic-gate 			break;
28260Sstevel@tonic-gate 		}
28270Sstevel@tonic-gate 	}
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate 	if (sigdata != NULL) {
28300Sstevel@tonic-gate 		crypto_es_hash(mp, sigdata + shp->sh_size, shstrtab);
28310Sstevel@tonic-gate 	}
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate 	kobj_free(shstrtab, shstrlen);
28340Sstevel@tonic-gate }
28350Sstevel@tonic-gate 
28360Sstevel@tonic-gate static void
28370Sstevel@tonic-gate add_dependent(struct module *mp, struct module *dep)
28380Sstevel@tonic-gate {
28390Sstevel@tonic-gate 	struct module_list *lp;
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 	for (lp = mp->head; lp; lp = lp->next) {
28420Sstevel@tonic-gate 		if (lp->mp == dep)
28430Sstevel@tonic-gate 			return;	/* already on the list */
28440Sstevel@tonic-gate 	}
28450Sstevel@tonic-gate 
28460Sstevel@tonic-gate 	if (lp == NULL) {
28470Sstevel@tonic-gate 		lp = kobj_zalloc(sizeof (*lp), KM_WAIT);
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate 		lp->mp = dep;
28500Sstevel@tonic-gate 		lp->next = NULL;
28510Sstevel@tonic-gate 		if (mp->tail)
28520Sstevel@tonic-gate 			mp->tail->next = lp;
28530Sstevel@tonic-gate 		else
28540Sstevel@tonic-gate 			mp->head = lp;
28550Sstevel@tonic-gate 		mp->tail = lp;
28560Sstevel@tonic-gate 	}
28570Sstevel@tonic-gate }
28580Sstevel@tonic-gate 
28590Sstevel@tonic-gate static int
28600Sstevel@tonic-gate do_dependents(struct modctl *modp, char *modname, size_t modnamelen)
28610Sstevel@tonic-gate {
28620Sstevel@tonic-gate 	struct module *mp;
28630Sstevel@tonic-gate 	struct modctl *req;
28640Sstevel@tonic-gate 	char *d, *p, *q;
28650Sstevel@tonic-gate 	int c;
28660Sstevel@tonic-gate 	char *err_modname = NULL;
28670Sstevel@tonic-gate 
28680Sstevel@tonic-gate 	mp = modp->mod_mp;
28690Sstevel@tonic-gate 
28700Sstevel@tonic-gate 	if ((p = mp->depends_on) == NULL)
28710Sstevel@tonic-gate 		return (0);
28720Sstevel@tonic-gate 
28730Sstevel@tonic-gate 	for (;;) {
28740Sstevel@tonic-gate 		/*
28750Sstevel@tonic-gate 		 * Skip space.
28760Sstevel@tonic-gate 		 */
28770Sstevel@tonic-gate 		while (*p && (*p == ' ' || *p == '\t'))
28780Sstevel@tonic-gate 			p++;
28790Sstevel@tonic-gate 		/*
28800Sstevel@tonic-gate 		 * Get module name.
28810Sstevel@tonic-gate 		 */
28820Sstevel@tonic-gate 		d = p;
28830Sstevel@tonic-gate 		q = modname;
28840Sstevel@tonic-gate 		c = 0;
28850Sstevel@tonic-gate 		while (*p && *p != ' ' && *p != '\t') {
28860Sstevel@tonic-gate 			if (c < modnamelen - 1) {
28870Sstevel@tonic-gate 				*q++ = *p;
28880Sstevel@tonic-gate 				c++;
28890Sstevel@tonic-gate 			}
28900Sstevel@tonic-gate 			p++;
28910Sstevel@tonic-gate 		}
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 		if (q == modname)
28940Sstevel@tonic-gate 			break;
28950Sstevel@tonic-gate 
28960Sstevel@tonic-gate 		if (c == modnamelen - 1) {
28970Sstevel@tonic-gate 			char *dep = kobj_alloc(p - d + 1, KM_WAIT|KM_TMP);
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate 			(void) strncpy(dep, d,  p - d + 1);
29000Sstevel@tonic-gate 			dep[p - d] = '\0';
29010Sstevel@tonic-gate 
29020Sstevel@tonic-gate 			_kobj_printf(ops, "%s: dependency ", modp->mod_modname);
29030Sstevel@tonic-gate 			_kobj_printf(ops, "'%s' too long ", dep);
29040Sstevel@tonic-gate 			_kobj_printf(ops, "(max %d chars)\n", modnamelen);
29050Sstevel@tonic-gate 
29060Sstevel@tonic-gate 			kobj_free(dep, p - d + 1);
29070Sstevel@tonic-gate 
29080Sstevel@tonic-gate 			return (-1);
29090Sstevel@tonic-gate 		}
29100Sstevel@tonic-gate 
29110Sstevel@tonic-gate 		*q = '\0';
29120Sstevel@tonic-gate 		if ((req = mod_load_requisite(modp, modname)) == NULL) {
29130Sstevel@tonic-gate #ifndef	KOBJ_DEBUG
29140Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_LOADMSG) {
29150Sstevel@tonic-gate #endif	/* KOBJ_DEBUG */
29160Sstevel@tonic-gate 				_kobj_printf(ops,
29170Sstevel@tonic-gate 				    "%s: unable to resolve dependency, ",
29180Sstevel@tonic-gate 				    modp->mod_modname);
29190Sstevel@tonic-gate 				_kobj_printf(ops, "cannot load module '%s'\n",
29200Sstevel@tonic-gate 				    modname);
29210Sstevel@tonic-gate #ifndef	KOBJ_DEBUG
29220Sstevel@tonic-gate 			}
29230Sstevel@tonic-gate #endif	/* KOBJ_DEBUG */
29240Sstevel@tonic-gate 			if (err_modname == NULL) {
29250Sstevel@tonic-gate 				/*
29260Sstevel@tonic-gate 				 * This must be the same size as the modname
29270Sstevel@tonic-gate 				 * one.
29280Sstevel@tonic-gate 				 */
29290Sstevel@tonic-gate 				err_modname = kobj_zalloc(MODMAXNAMELEN,
29300Sstevel@tonic-gate 				    KM_WAIT);
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 				/*
29330Sstevel@tonic-gate 				 * We can use strcpy() here without fearing
29340Sstevel@tonic-gate 				 * the NULL terminator because the size of
29350Sstevel@tonic-gate 				 * err_modname is the same as one of modname,
29360Sstevel@tonic-gate 				 * and it's filled with zeros.
29370Sstevel@tonic-gate 				 */
29380Sstevel@tonic-gate 				(void) strcpy(err_modname, modname);
29390Sstevel@tonic-gate 			}
29400Sstevel@tonic-gate 			continue;
29410Sstevel@tonic-gate 		}
29420Sstevel@tonic-gate 
29430Sstevel@tonic-gate 		add_dependent(mp, req->mod_mp);
29440Sstevel@tonic-gate 		mod_release_mod(req);
29450Sstevel@tonic-gate 
29460Sstevel@tonic-gate 	}
29470Sstevel@tonic-gate 
29480Sstevel@tonic-gate 	if (err_modname != NULL) {
29490Sstevel@tonic-gate 		/*
29500Sstevel@tonic-gate 		 * Copy the first module name where you detect an error to keep
29510Sstevel@tonic-gate 		 * its behavior the same as before.
29520Sstevel@tonic-gate 		 * This way keeps minimizing the memory use for error
29530Sstevel@tonic-gate 		 * modules, and this might be important at boot time because
29540Sstevel@tonic-gate 		 * the memory usage is a crucial factor for booting in most
29550Sstevel@tonic-gate 		 * cases. You can expect more verbose messages when using
29560Sstevel@tonic-gate 		 * a debug kernel or setting a bit in moddebug.
29570Sstevel@tonic-gate 		 */
29580Sstevel@tonic-gate 		bzero(modname, MODMAXNAMELEN);
29590Sstevel@tonic-gate 		(void) strcpy(modname, err_modname);
29600Sstevel@tonic-gate 		kobj_free(err_modname, MODMAXNAMELEN);
29610Sstevel@tonic-gate 		return (-1);
29620Sstevel@tonic-gate 	}
29630Sstevel@tonic-gate 
29640Sstevel@tonic-gate 	return (0);
29650Sstevel@tonic-gate }
29660Sstevel@tonic-gate 
29670Sstevel@tonic-gate static int
29680Sstevel@tonic-gate do_common(struct module *mp)
29690Sstevel@tonic-gate {
29700Sstevel@tonic-gate 	int err;
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate 	/*
29730Sstevel@tonic-gate 	 * first time through, assign all symbols defined in other
29740Sstevel@tonic-gate 	 * modules, and count up how much common space will be needed
29750Sstevel@tonic-gate 	 * (bss_size and bss_align)
29760Sstevel@tonic-gate 	 */
29770Sstevel@tonic-gate 	if ((err = do_symbols(mp, 0)) < 0)
29780Sstevel@tonic-gate 		return (err);
29790Sstevel@tonic-gate 	/*
29800Sstevel@tonic-gate 	 * increase bss_size by the maximum delta that could be
29810Sstevel@tonic-gate 	 * computed by the ALIGN below
29820Sstevel@tonic-gate 	 */
29830Sstevel@tonic-gate 	mp->bss_size += mp->bss_align;
29840Sstevel@tonic-gate 	if (mp->bss_size) {
29850Sstevel@tonic-gate 		if (standalone)
29860Sstevel@tonic-gate 			mp->bss = (uintptr_t)kobj_segbrk(&_edata, mp->bss_size,
29870Sstevel@tonic-gate 			    MINALIGN, 0);
29880Sstevel@tonic-gate 		else
29890Sstevel@tonic-gate 			mp->bss = (uintptr_t)vmem_alloc(data_arena,
29900Sstevel@tonic-gate 			    mp->bss_size, VM_SLEEP | VM_BESTFIT);
29910Sstevel@tonic-gate 		bzero((void *)mp->bss, mp->bss_size);
29920Sstevel@tonic-gate 		/* now assign addresses to all common symbols */
29930Sstevel@tonic-gate 		if ((err = do_symbols(mp, ALIGN(mp->bss, mp->bss_align))) < 0)
29940Sstevel@tonic-gate 			return (err);
29950Sstevel@tonic-gate 	}
29960Sstevel@tonic-gate 	return (0);
29970Sstevel@tonic-gate }
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate static int
30000Sstevel@tonic-gate do_symbols(struct module *mp, Elf64_Addr bss_base)
30010Sstevel@tonic-gate {
30020Sstevel@tonic-gate 	int bss_align;
30030Sstevel@tonic-gate 	uintptr_t bss_ptr;
30040Sstevel@tonic-gate 	int err;
30050Sstevel@tonic-gate 	int i;
30060Sstevel@tonic-gate 	Sym *sp, *sp1;
30070Sstevel@tonic-gate 	char *name;
30080Sstevel@tonic-gate 	int assign;
30090Sstevel@tonic-gate 	int resolved = 1;
30100Sstevel@tonic-gate 
30110Sstevel@tonic-gate 	/*
30120Sstevel@tonic-gate 	 * Nothing left to do (optimization).
30130Sstevel@tonic-gate 	 */
30140Sstevel@tonic-gate 	if (mp->flags & KOBJ_RESOLVED)
30150Sstevel@tonic-gate 		return (0);
30160Sstevel@tonic-gate 
30170Sstevel@tonic-gate 	assign = (bss_base) ? 1 : 0;
30180Sstevel@tonic-gate 	bss_ptr = bss_base;
30190Sstevel@tonic-gate 	bss_align = 0;
30200Sstevel@tonic-gate 	err = 0;
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	for (i = 1; i < mp->nsyms; i++) {
30230Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + mp->symhdr->sh_entsize * i);
30240Sstevel@tonic-gate 		/*
30250Sstevel@tonic-gate 		 * we know that st_name is in bounds, since get_sections
30260Sstevel@tonic-gate 		 * has already checked all of the symbols
30270Sstevel@tonic-gate 		 */
30280Sstevel@tonic-gate 		name = mp->strings + sp->st_name;
30290Sstevel@tonic-gate 		if (sp->st_shndx != SHN_UNDEF && sp->st_shndx != SHN_COMMON)
30300Sstevel@tonic-gate 			continue;
30310Sstevel@tonic-gate #ifdef	__sparc
30320Sstevel@tonic-gate 		/*
30330Sstevel@tonic-gate 		 * Register symbols are ignored in the kernel
30340Sstevel@tonic-gate 		 */
30350Sstevel@tonic-gate 		if (ELF_ST_TYPE(sp->st_info) == STT_SPARC_REGISTER) {
30360Sstevel@tonic-gate 			if (*name != '\0') {
30370Sstevel@tonic-gate 				_kobj_printf(ops, "%s: named REGISTER symbol ",
30383912Slling 				    mp->filename);
30390Sstevel@tonic-gate 				_kobj_printf(ops, "not supported '%s'\n",
30403912Slling 				    name);
30410Sstevel@tonic-gate 				err = DOSYM_UNDEF;
30420Sstevel@tonic-gate 			}
30430Sstevel@tonic-gate 			continue;
30440Sstevel@tonic-gate 		}
30450Sstevel@tonic-gate #endif	/* __sparc */
30460Sstevel@tonic-gate 		/*
30470Sstevel@tonic-gate 		 * TLS symbols are ignored in the kernel
30480Sstevel@tonic-gate 		 */
30490Sstevel@tonic-gate 		if (ELF_ST_TYPE(sp->st_info) == STT_TLS) {
30500Sstevel@tonic-gate 			_kobj_printf(ops, "%s: TLS symbol ",
30513912Slling 			    mp->filename);
30520Sstevel@tonic-gate 			_kobj_printf(ops, "not supported '%s'\n",
30533912Slling 			    name);
30540Sstevel@tonic-gate 			err = DOSYM_UNDEF;
30550Sstevel@tonic-gate 			continue;
30560Sstevel@tonic-gate 		}
30570Sstevel@tonic-gate 
30580Sstevel@tonic-gate 		if (ELF_ST_BIND(sp->st_info) != STB_LOCAL) {
30590Sstevel@tonic-gate 			if ((sp1 = kobj_lookup_all(mp, name, 0)) != NULL) {
30600Sstevel@tonic-gate 				sp->st_shndx = SHN_ABS;
30610Sstevel@tonic-gate 				sp->st_value = sp1->st_value;
30620Sstevel@tonic-gate 				continue;
30630Sstevel@tonic-gate 			}
30640Sstevel@tonic-gate 		}
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate 		if (sp->st_shndx == SHN_UNDEF) {
30670Sstevel@tonic-gate 			resolved = 0;
30680Sstevel@tonic-gate 
30690Sstevel@tonic-gate 			if (strncmp(name, sdt_prefix, strlen(sdt_prefix)) == 0)
30700Sstevel@tonic-gate 				continue;
30710Sstevel@tonic-gate 
30720Sstevel@tonic-gate 			/*
30730Sstevel@tonic-gate 			 * If it's not a weak reference and it's
30740Sstevel@tonic-gate 			 * not a primary object, it's an error.
30750Sstevel@tonic-gate 			 * (Primary objects may take more than
30760Sstevel@tonic-gate 			 * one pass to resolve)
30770Sstevel@tonic-gate 			 */
30780Sstevel@tonic-gate 			if (!(mp->flags & KOBJ_PRIM) &&
30790Sstevel@tonic-gate 			    ELF_ST_BIND(sp->st_info) != STB_WEAK) {
30800Sstevel@tonic-gate 				_kobj_printf(ops, "%s: undefined symbol",
30810Sstevel@tonic-gate 				    mp->filename);
30820Sstevel@tonic-gate 				_kobj_printf(ops, " '%s'\n", name);
30830Sstevel@tonic-gate 				/*
30840Sstevel@tonic-gate 				 * Try to determine whether this symbol
30850Sstevel@tonic-gate 				 * represents a dependency on obsolete
30860Sstevel@tonic-gate 				 * unsafe driver support.  This is just
30870Sstevel@tonic-gate 				 * to make the warning more informative.
30880Sstevel@tonic-gate 				 */
30890Sstevel@tonic-gate 				if (strcmp(name, "sleep") == 0 ||
30900Sstevel@tonic-gate 				    strcmp(name, "unsleep") == 0 ||
30910Sstevel@tonic-gate 				    strcmp(name, "wakeup") == 0 ||
30920Sstevel@tonic-gate 				    strcmp(name, "bsd_compat_ioctl") == 0 ||
30930Sstevel@tonic-gate 				    strcmp(name, "unsafe_driver") == 0 ||
30940Sstevel@tonic-gate 				    strncmp(name, "spl", 3) == 0 ||
30950Sstevel@tonic-gate 				    strncmp(name, "i_ddi_spl", 9) == 0)
30960Sstevel@tonic-gate 					err = DOSYM_UNSAFE;
30970Sstevel@tonic-gate 				if (err == 0)
30980Sstevel@tonic-gate 					err = DOSYM_UNDEF;
30990Sstevel@tonic-gate 			}
31000Sstevel@tonic-gate 			continue;
31010Sstevel@tonic-gate 		}
31020Sstevel@tonic-gate 		/*
31030Sstevel@tonic-gate 		 * It's a common symbol - st_value is the
31040Sstevel@tonic-gate 		 * required alignment.
31050Sstevel@tonic-gate 		 */
31060Sstevel@tonic-gate 		if (sp->st_value > bss_align)
31070Sstevel@tonic-gate 			bss_align = sp->st_value;
31080Sstevel@tonic-gate 		bss_ptr = ALIGN(bss_ptr, sp->st_value);
31090Sstevel@tonic-gate 		if (assign) {
31100Sstevel@tonic-gate 			sp->st_shndx = SHN_ABS;
31110Sstevel@tonic-gate 			sp->st_value = bss_ptr;
31120Sstevel@tonic-gate 		}
31130Sstevel@tonic-gate 		bss_ptr += sp->st_size;
31140Sstevel@tonic-gate 	}
31150Sstevel@tonic-gate 	if (err)
31160Sstevel@tonic-gate 		return (err);
31170Sstevel@tonic-gate 	if (assign == 0 && mp->bss == NULL) {
31180Sstevel@tonic-gate 		mp->bss_align = bss_align;
31190Sstevel@tonic-gate 		mp->bss_size = bss_ptr;
31200Sstevel@tonic-gate 	} else if (resolved) {
31210Sstevel@tonic-gate 		mp->flags |= KOBJ_RESOLVED;
31220Sstevel@tonic-gate 	}
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate 	return (0);
31250Sstevel@tonic-gate }
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate uint_t
31280Sstevel@tonic-gate kobj_hash_name(const char *p)
31290Sstevel@tonic-gate {
31300Sstevel@tonic-gate 	unsigned int g;
31310Sstevel@tonic-gate 	uint_t hval;
31320Sstevel@tonic-gate 
31330Sstevel@tonic-gate 	hval = 0;
31340Sstevel@tonic-gate 	while (*p) {
31350Sstevel@tonic-gate 		hval = (hval << 4) + *p++;
31360Sstevel@tonic-gate 		if ((g = (hval & 0xf0000000)) != 0)
31370Sstevel@tonic-gate 			hval ^= g >> 24;
31380Sstevel@tonic-gate 		hval &= ~g;
31390Sstevel@tonic-gate 	}
31400Sstevel@tonic-gate 	return (hval);
31410Sstevel@tonic-gate }
31420Sstevel@tonic-gate 
31430Sstevel@tonic-gate /* look for name in all modules */
31440Sstevel@tonic-gate uintptr_t
31450Sstevel@tonic-gate kobj_getsymvalue(char *name, int kernelonly)
31460Sstevel@tonic-gate {
31470Sstevel@tonic-gate 	Sym		*sp;
31480Sstevel@tonic-gate 	struct modctl	*modp;
31490Sstevel@tonic-gate 	struct module	*mp;
31500Sstevel@tonic-gate 	uintptr_t	value = 0;
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 	if ((sp = kobj_lookup_kernel(name)) != NULL)
31530Sstevel@tonic-gate 		return ((uintptr_t)sp->st_value);
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	if (kernelonly)
31560Sstevel@tonic-gate 		return (0);	/* didn't find it in the kernel so give up */
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	mutex_enter(&mod_lock);
31590Sstevel@tonic-gate 	modp = &modules;
31600Sstevel@tonic-gate 	do {
31610Sstevel@tonic-gate 		mp = (struct module *)modp->mod_mp;
31620Sstevel@tonic-gate 		if (mp && !(mp->flags & KOBJ_PRIM) && modp->mod_loaded &&
31630Sstevel@tonic-gate 		    (sp = lookup_one(mp, name))) {
31640Sstevel@tonic-gate 			value = (uintptr_t)sp->st_value;
31650Sstevel@tonic-gate 			break;
31660Sstevel@tonic-gate 		}
31670Sstevel@tonic-gate 	} while ((modp = modp->mod_next) != &modules);
31680Sstevel@tonic-gate 	mutex_exit(&mod_lock);
31690Sstevel@tonic-gate 	return (value);
31700Sstevel@tonic-gate }
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate /* look for a symbol near value. */
31730Sstevel@tonic-gate char *
31740Sstevel@tonic-gate kobj_getsymname(uintptr_t value, ulong_t *offset)
31750Sstevel@tonic-gate {
31760Sstevel@tonic-gate 	char *name = NULL;
31770Sstevel@tonic-gate 	struct modctl *modp;
31780Sstevel@tonic-gate 
31790Sstevel@tonic-gate 	struct modctl_list *lp;
31800Sstevel@tonic-gate 	struct module *mp;
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate 	/*
31830Sstevel@tonic-gate 	 * Loop through the primary kernel modules.
31840Sstevel@tonic-gate 	 */
31850Sstevel@tonic-gate 	for (lp = kobj_lm_lookup(KOBJ_LM_PRIMARY); lp; lp = lp->modl_next) {
31860Sstevel@tonic-gate 		mp = mod(lp);
31870Sstevel@tonic-gate 
31880Sstevel@tonic-gate 		if ((name = kobj_searchsym(mp, value, offset)) != NULL)
31890Sstevel@tonic-gate 			return (name);
31900Sstevel@tonic-gate 	}
31910Sstevel@tonic-gate 
31920Sstevel@tonic-gate 	mutex_enter(&mod_lock);
31930Sstevel@tonic-gate 	modp = &modules;
31940Sstevel@tonic-gate 	do {
31950Sstevel@tonic-gate 		mp = (struct module *)modp->mod_mp;
31960Sstevel@tonic-gate 		if (mp && !(mp->flags & KOBJ_PRIM) && modp->mod_loaded &&
31970Sstevel@tonic-gate 		    (name = kobj_searchsym(mp, value, offset)))
31980Sstevel@tonic-gate 			break;
31990Sstevel@tonic-gate 	} while ((modp = modp->mod_next) != &modules);
32000Sstevel@tonic-gate 	mutex_exit(&mod_lock);
32010Sstevel@tonic-gate 	return (name);
32020Sstevel@tonic-gate }
32030Sstevel@tonic-gate 
32040Sstevel@tonic-gate /* return address of symbol and size */
32050Sstevel@tonic-gate 
32060Sstevel@tonic-gate uintptr_t
32070Sstevel@tonic-gate kobj_getelfsym(char *name, void *mp, int *size)
32080Sstevel@tonic-gate {
32090Sstevel@tonic-gate 	Sym *sp;
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate 	if (mp == NULL)
32120Sstevel@tonic-gate 		sp = kobj_lookup_kernel(name);
32130Sstevel@tonic-gate 	else
32140Sstevel@tonic-gate 		sp = lookup_one(mp, name);
32150Sstevel@tonic-gate 
32160Sstevel@tonic-gate 	if (sp == NULL)
32170Sstevel@tonic-gate 		return (0);
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	*size = (int)sp->st_size;
32200Sstevel@tonic-gate 	return ((uintptr_t)sp->st_value);
32210Sstevel@tonic-gate }
32220Sstevel@tonic-gate 
32230Sstevel@tonic-gate uintptr_t
32241414Scindi kobj_lookup(struct module *mod, const char *name)
32250Sstevel@tonic-gate {
32260Sstevel@tonic-gate 	Sym *sp;
32270Sstevel@tonic-gate 
32280Sstevel@tonic-gate 	sp = lookup_one(mod, name);
32290Sstevel@tonic-gate 
32300Sstevel@tonic-gate 	if (sp == NULL)
32310Sstevel@tonic-gate 		return (0);
32320Sstevel@tonic-gate 
32330Sstevel@tonic-gate 	return ((uintptr_t)sp->st_value);
32340Sstevel@tonic-gate }
32350Sstevel@tonic-gate 
32360Sstevel@tonic-gate char *
32370Sstevel@tonic-gate kobj_searchsym(struct module *mp, uintptr_t value, ulong_t *offset)
32380Sstevel@tonic-gate {
32390Sstevel@tonic-gate 	Sym *symtabptr;
32400Sstevel@tonic-gate 	char *strtabptr;
32410Sstevel@tonic-gate 	int symnum;
32420Sstevel@tonic-gate 	Sym *sym;
32430Sstevel@tonic-gate 	Sym *cursym;
32440Sstevel@tonic-gate 	uintptr_t curval;
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate 	*offset = (ulong_t)-1l;		/* assume not found */
32470Sstevel@tonic-gate 	cursym  = NULL;
32480Sstevel@tonic-gate 
32490Sstevel@tonic-gate 	if (kobj_addrcheck(mp, (void *)value) != 0)
32500Sstevel@tonic-gate 		return (NULL);		/* not in this module */
32510Sstevel@tonic-gate 
32520Sstevel@tonic-gate 	strtabptr  = mp->strings;
32530Sstevel@tonic-gate 	symtabptr  = (Sym *)mp->symtbl;
32540Sstevel@tonic-gate 
32550Sstevel@tonic-gate 	/*
32560Sstevel@tonic-gate 	 * Scan the module's symbol table for a symbol <= value
32570Sstevel@tonic-gate 	 */
32580Sstevel@tonic-gate 	for (symnum = 1, sym = symtabptr + 1;
32590Sstevel@tonic-gate 	    symnum < mp->nsyms; symnum++, sym = (Sym *)
32600Sstevel@tonic-gate 	    ((uintptr_t)sym + mp->symhdr->sh_entsize)) {
32610Sstevel@tonic-gate 		if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
32620Sstevel@tonic-gate 			if (ELF_ST_BIND(sym->st_info) != STB_LOCAL)
32630Sstevel@tonic-gate 				continue;
32640Sstevel@tonic-gate 			if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
32650Sstevel@tonic-gate 			    ELF_ST_TYPE(sym->st_info) != STT_FUNC)
32660Sstevel@tonic-gate 				continue;
32670Sstevel@tonic-gate 		}
32680Sstevel@tonic-gate 
32690Sstevel@tonic-gate 		curval = (uintptr_t)sym->st_value;
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate 		if (curval > value)
32720Sstevel@tonic-gate 			continue;
32730Sstevel@tonic-gate 
32740Sstevel@tonic-gate 		/*
32750Sstevel@tonic-gate 		 * If one or both are functions...
32760Sstevel@tonic-gate 		 */
32770Sstevel@tonic-gate 		if (ELF_ST_TYPE(sym->st_info) == STT_FUNC || (cursym != NULL &&
32780Sstevel@tonic-gate 		    ELF_ST_TYPE(cursym->st_info) == STT_FUNC)) {
32790Sstevel@tonic-gate 			/* Ignore if the address is out of the bounds */
32800Sstevel@tonic-gate 			if (value - sym->st_value >= sym->st_size)
32810Sstevel@tonic-gate 				continue;
32820Sstevel@tonic-gate 
32830Sstevel@tonic-gate 			if (cursym != NULL &&
32840Sstevel@tonic-gate 			    ELF_ST_TYPE(cursym->st_info) == STT_FUNC) {
32850Sstevel@tonic-gate 				/* Prefer the function to the non-function */
32860Sstevel@tonic-gate 				if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
32870Sstevel@tonic-gate 					continue;
32880Sstevel@tonic-gate 
32890Sstevel@tonic-gate 				/* Prefer the larger of the two functions */
32900Sstevel@tonic-gate 				if (sym->st_size <= cursym->st_size)
32910Sstevel@tonic-gate 					continue;
32920Sstevel@tonic-gate 			}
32930Sstevel@tonic-gate 		} else if (value - curval >= *offset) {
32940Sstevel@tonic-gate 			continue;
32950Sstevel@tonic-gate 		}
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate 		*offset = (ulong_t)(value - curval);
32980Sstevel@tonic-gate 		cursym = sym;
32990Sstevel@tonic-gate 	}
33000Sstevel@tonic-gate 	if (cursym == NULL)
33010Sstevel@tonic-gate 		return (NULL);
33020Sstevel@tonic-gate 
33030Sstevel@tonic-gate 	return (strtabptr + cursym->st_name);
33040Sstevel@tonic-gate }
33050Sstevel@tonic-gate 
33060Sstevel@tonic-gate Sym *
33070Sstevel@tonic-gate kobj_lookup_all(struct module *mp, char *name, int include_self)
33080Sstevel@tonic-gate {
33090Sstevel@tonic-gate 	Sym *sp;
33100Sstevel@tonic-gate 	struct module_list *mlp;
33110Sstevel@tonic-gate 	struct modctl_list *clp;
33120Sstevel@tonic-gate 	struct module *mmp;
33130Sstevel@tonic-gate 
33140Sstevel@tonic-gate 	if (include_self && (sp = lookup_one(mp, name)) != NULL)
33150Sstevel@tonic-gate 		return (sp);
33160Sstevel@tonic-gate 
33170Sstevel@tonic-gate 	for (mlp = mp->head; mlp; mlp = mlp->next) {
33180Sstevel@tonic-gate 		if ((sp = lookup_one(mlp->mp, name)) != NULL &&
33190Sstevel@tonic-gate 		    ELF_ST_BIND(sp->st_info) != STB_LOCAL)
33200Sstevel@tonic-gate 			return (sp);
33210Sstevel@tonic-gate 	}
33220Sstevel@tonic-gate 
33230Sstevel@tonic-gate 	/*
33240Sstevel@tonic-gate 	 * Loop through the primary kernel modules.
33250Sstevel@tonic-gate 	 */
33260Sstevel@tonic-gate 	for (clp = kobj_lm_lookup(KOBJ_LM_PRIMARY); clp; clp = clp->modl_next) {
33270Sstevel@tonic-gate 		mmp = mod(clp);
33280Sstevel@tonic-gate 
33290Sstevel@tonic-gate 		if (mmp == NULL || mp == mmp)
33300Sstevel@tonic-gate 			continue;
33310Sstevel@tonic-gate 
33320Sstevel@tonic-gate 		if ((sp = lookup_one(mmp, name)) != NULL &&
33330Sstevel@tonic-gate 		    ELF_ST_BIND(sp->st_info) != STB_LOCAL)
33340Sstevel@tonic-gate 			return (sp);
33350Sstevel@tonic-gate 	}
33360Sstevel@tonic-gate 	return (NULL);
33370Sstevel@tonic-gate }
33380Sstevel@tonic-gate 
33390Sstevel@tonic-gate Sym *
33400Sstevel@tonic-gate kobj_lookup_kernel(const char *name)
33410Sstevel@tonic-gate {
33420Sstevel@tonic-gate 	struct modctl_list *lp;
33430Sstevel@tonic-gate 	struct module *mp;
33440Sstevel@tonic-gate 	Sym *sp;
33450Sstevel@tonic-gate 
33460Sstevel@tonic-gate 	/*
33470Sstevel@tonic-gate 	 * Loop through the primary kernel modules.
33480Sstevel@tonic-gate 	 */
33490Sstevel@tonic-gate 	for (lp = kobj_lm_lookup(KOBJ_LM_PRIMARY); lp; lp = lp->modl_next) {
33500Sstevel@tonic-gate 		mp = mod(lp);
33510Sstevel@tonic-gate 
33520Sstevel@tonic-gate 		if (mp == NULL)
33530Sstevel@tonic-gate 			continue;
33540Sstevel@tonic-gate 
33550Sstevel@tonic-gate 		if ((sp = lookup_one(mp, name)) != NULL)
33560Sstevel@tonic-gate 			return (sp);
33570Sstevel@tonic-gate 	}
33580Sstevel@tonic-gate 	return (NULL);
33590Sstevel@tonic-gate }
33600Sstevel@tonic-gate 
33610Sstevel@tonic-gate static Sym *
33620Sstevel@tonic-gate lookup_one(struct module *mp, const char *name)
33630Sstevel@tonic-gate {
33640Sstevel@tonic-gate 	symid_t *ip;
33650Sstevel@tonic-gate 	char *name1;
33660Sstevel@tonic-gate 	Sym *sp;
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate 	for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
33690Sstevel@tonic-gate 	    ip = &mp->chains[*ip]) {
33700Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl +
33710Sstevel@tonic-gate 		    mp->symhdr->sh_entsize * *ip);
33720Sstevel@tonic-gate 		name1 = mp->strings + sp->st_name;
33730Sstevel@tonic-gate 		if (strcmp(name, name1) == 0 &&
33740Sstevel@tonic-gate 		    ELF_ST_TYPE(sp->st_info) != STT_FILE &&
33750Sstevel@tonic-gate 		    sp->st_shndx != SHN_UNDEF &&
33760Sstevel@tonic-gate 		    sp->st_shndx != SHN_COMMON)
33770Sstevel@tonic-gate 			return (sp);
33780Sstevel@tonic-gate 	}
33790Sstevel@tonic-gate 	return (NULL);
33800Sstevel@tonic-gate }
33810Sstevel@tonic-gate 
33820Sstevel@tonic-gate /*
33830Sstevel@tonic-gate  * Lookup a given symbol pointer in the module's symbol hash.  If the symbol
33840Sstevel@tonic-gate  * is hashed, return the symbol pointer; otherwise return NULL.
33850Sstevel@tonic-gate  */
33860Sstevel@tonic-gate static Sym *
33870Sstevel@tonic-gate sym_lookup(struct module *mp, Sym *ksp)
33880Sstevel@tonic-gate {
33890Sstevel@tonic-gate 	char *name = mp->strings + ksp->st_name;
33900Sstevel@tonic-gate 	symid_t *ip;
33910Sstevel@tonic-gate 	Sym *sp;
33920Sstevel@tonic-gate 
33930Sstevel@tonic-gate 	for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
33940Sstevel@tonic-gate 	    ip = &mp->chains[*ip]) {
33950Sstevel@tonic-gate 		sp = (Sym *)(mp->symtbl + mp->symhdr->sh_entsize * *ip);
33960Sstevel@tonic-gate 		if (sp == ksp)
33970Sstevel@tonic-gate 			return (ksp);
33980Sstevel@tonic-gate 	}
33990Sstevel@tonic-gate 	return (NULL);
34000Sstevel@tonic-gate }
34010Sstevel@tonic-gate 
34020Sstevel@tonic-gate static void
34030Sstevel@tonic-gate sym_insert(struct module *mp, char *name, symid_t index)
34040Sstevel@tonic-gate {
34050Sstevel@tonic-gate 	symid_t *ip;
34060Sstevel@tonic-gate 
34070Sstevel@tonic-gate #ifdef KOBJ_DEBUG
34080Sstevel@tonic-gate 		if (kobj_debug & D_SYMBOLS) {
34090Sstevel@tonic-gate 			static struct module *lastmp = NULL;
34100Sstevel@tonic-gate 			Sym *sp;
34110Sstevel@tonic-gate 			if (lastmp != mp) {
34120Sstevel@tonic-gate 				_kobj_printf(ops,
34130Sstevel@tonic-gate 				    "krtld: symbol entry: file=%s\n",
34140Sstevel@tonic-gate 				    mp->filename);
34150Sstevel@tonic-gate 				_kobj_printf(ops,
34160Sstevel@tonic-gate 				    "krtld:\tsymndx\tvalue\t\t"
34170Sstevel@tonic-gate 				    "symbol name\n");
34180Sstevel@tonic-gate 				lastmp = mp;
34190Sstevel@tonic-gate 			}
34200Sstevel@tonic-gate 			sp = (Sym *)(mp->symtbl +
34213912Slling 			    index * mp->symhdr->sh_entsize);
34220Sstevel@tonic-gate 			_kobj_printf(ops, "krtld:\t[%3d]", index);
34230Sstevel@tonic-gate 			_kobj_printf(ops, "\t0x%lx", sp->st_value);
34240Sstevel@tonic-gate 			_kobj_printf(ops, "\t%s\n", name);
34250Sstevel@tonic-gate 		}
34260Sstevel@tonic-gate 
34270Sstevel@tonic-gate #endif
34280Sstevel@tonic-gate 	for (ip = &mp->buckets[kobj_hash_name(name) % mp->hashsize]; *ip;
34290Sstevel@tonic-gate 	    ip = &mp->chains[*ip]) {
34300Sstevel@tonic-gate 		;
34310Sstevel@tonic-gate 	}
34320Sstevel@tonic-gate 	*ip = index;
34330Sstevel@tonic-gate }
34340Sstevel@tonic-gate 
34350Sstevel@tonic-gate struct modctl *
34360Sstevel@tonic-gate kobj_boot_mod_lookup(const char *modname)
34370Sstevel@tonic-gate {
34380Sstevel@tonic-gate 	struct modctl *mctl = kobj_modules;
34390Sstevel@tonic-gate 
34400Sstevel@tonic-gate 	do {
34410Sstevel@tonic-gate 		if (strcmp(modname, mctl->mod_modname) == 0)
34420Sstevel@tonic-gate 			return (mctl);
34430Sstevel@tonic-gate 	} while ((mctl = mctl->mod_next) != kobj_modules);
34440Sstevel@tonic-gate 
34450Sstevel@tonic-gate 	return (NULL);
34460Sstevel@tonic-gate }
34470Sstevel@tonic-gate 
34480Sstevel@tonic-gate /*
3449309Scth  * Determine if the module exists.
3450309Scth  */
3451309Scth int
3452309Scth kobj_path_exists(char *name, int use_path)
3453309Scth {
3454309Scth 	struct _buf *file;
3455309Scth 
3456309Scth 	file = kobj_open_path(name, use_path, 1);
3457309Scth #ifdef	MODDIR_SUFFIX
3458309Scth 	if (file == (struct _buf *)-1)
3459309Scth 		file = kobj_open_path(name, use_path, 0);
3460309Scth #endif	/* MODDIR_SUFFIX */
3461309Scth 	if (file == (struct _buf *)-1)
3462309Scth 		return (0);
3463309Scth 	kobj_close_file(file);
3464309Scth 	return (1);
3465309Scth }
3466309Scth 
3467309Scth /*
34680Sstevel@tonic-gate  * fullname is dynamically allocated to be able to hold the
34690Sstevel@tonic-gate  * maximum size string that can be constructed from name.
34700Sstevel@tonic-gate  * path is exactly like the shell PATH variable.
34710Sstevel@tonic-gate  */
34720Sstevel@tonic-gate struct _buf *
34730Sstevel@tonic-gate kobj_open_path(char *name, int use_path, int use_moddir_suffix)
34740Sstevel@tonic-gate {
34750Sstevel@tonic-gate 	char *p, *q;
34760Sstevel@tonic-gate 	char *pathp;
34770Sstevel@tonic-gate 	char *pathpsave;
34780Sstevel@tonic-gate 	char *fullname;
34790Sstevel@tonic-gate 	int maxpathlen;
34800Sstevel@tonic-gate 	struct _buf *file;
34810Sstevel@tonic-gate 
34820Sstevel@tonic-gate #if !defined(MODDIR_SUFFIX)
34830Sstevel@tonic-gate 	use_moddir_suffix = B_FALSE;
34840Sstevel@tonic-gate #endif
34850Sstevel@tonic-gate 
34860Sstevel@tonic-gate 	if (!use_path)
34870Sstevel@tonic-gate 		pathp = "";		/* use name as specified */
34880Sstevel@tonic-gate 	else
34893446Smrj 		pathp = kobj_module_path;
34903446Smrj 					/* use configured default path */
34910Sstevel@tonic-gate 
34920Sstevel@tonic-gate 	pathpsave = pathp;		/* keep this for error reporting */
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate 	/*
34950Sstevel@tonic-gate 	 * Allocate enough space for the largest possible fullname.
34960Sstevel@tonic-gate 	 * since path is of the form <directory> : <directory> : ...
34970Sstevel@tonic-gate 	 * we're potentially allocating a little more than we need to
34980Sstevel@tonic-gate 	 * but we'll allocate the exact amount when we find the right directory.
34990Sstevel@tonic-gate 	 * (The + 3 below is one for NULL terminator and one for the '/'
35000Sstevel@tonic-gate 	 * we might have to add at the beginning of path and one for
35010Sstevel@tonic-gate 	 * the '/' between path and name.)
35020Sstevel@tonic-gate 	 */
35030Sstevel@tonic-gate 	maxpathlen = strlen(pathp) + strlen(name) + 3;
35040Sstevel@tonic-gate 	/* sizeof includes null */
35050Sstevel@tonic-gate 	maxpathlen += sizeof (slash_moddir_suffix_slash) - 1;
35060Sstevel@tonic-gate 	fullname = kobj_zalloc(maxpathlen, KM_WAIT);
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 	for (;;) {
35090Sstevel@tonic-gate 		p = fullname;
35100Sstevel@tonic-gate 		if (*pathp != '\0' && *pathp != '/')
35110Sstevel@tonic-gate 			*p++ = '/';	/* path must start with '/' */
35120Sstevel@tonic-gate 		while (*pathp && *pathp != ':' && *pathp != ' ')
35130Sstevel@tonic-gate 			*p++ = *pathp++;
35140Sstevel@tonic-gate 		if (p != fullname && p[-1] != '/')
35150Sstevel@tonic-gate 			*p++ = '/';
35160Sstevel@tonic-gate 		if (use_moddir_suffix) {
35170Sstevel@tonic-gate 			char *b = basename(name);
35180Sstevel@tonic-gate 			char *s;
35190Sstevel@tonic-gate 
35200Sstevel@tonic-gate 			/* copy everything up to the base name */
35210Sstevel@tonic-gate 			q = name;
35220Sstevel@tonic-gate 			while (q != b && *q)
35230Sstevel@tonic-gate 				*p++ = *q++;
35240Sstevel@tonic-gate 			s = slash_moddir_suffix_slash;
35250Sstevel@tonic-gate 			while (*s)
35260Sstevel@tonic-gate 				*p++ = *s++;
35270Sstevel@tonic-gate 			/* copy the rest */
35280Sstevel@tonic-gate 			while (*b)
35290Sstevel@tonic-gate 				*p++ = *b++;
35300Sstevel@tonic-gate 		} else {
35310Sstevel@tonic-gate 			q = name;
35320Sstevel@tonic-gate 			while (*q)
35330Sstevel@tonic-gate 				*p++ = *q++;
35340Sstevel@tonic-gate 		}
35350Sstevel@tonic-gate 		*p = 0;
35360Sstevel@tonic-gate 		if ((file = kobj_open_file(fullname)) != (struct _buf *)-1) {
35370Sstevel@tonic-gate 			kobj_free(fullname, maxpathlen);
35380Sstevel@tonic-gate 			return (file);
35390Sstevel@tonic-gate 		}
35400Sstevel@tonic-gate 		if (*pathp == 0)
35410Sstevel@tonic-gate 			break;
35420Sstevel@tonic-gate 		pathp++;
35430Sstevel@tonic-gate 	}
35440Sstevel@tonic-gate 	kobj_free(fullname, maxpathlen);
35450Sstevel@tonic-gate 	if (_moddebug & MODDEBUG_ERRMSG) {
35460Sstevel@tonic-gate 		_kobj_printf(ops, "can't open %s,", name);
35470Sstevel@tonic-gate 		_kobj_printf(ops, " path is %s\n", pathpsave);
35480Sstevel@tonic-gate 	}
35490Sstevel@tonic-gate 	return ((struct _buf *)-1);
35500Sstevel@tonic-gate }
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate intptr_t
35530Sstevel@tonic-gate kobj_open(char *filename)
35540Sstevel@tonic-gate {
35550Sstevel@tonic-gate 	struct vnode *vp;
35560Sstevel@tonic-gate 	int fd;
35570Sstevel@tonic-gate 
35580Sstevel@tonic-gate 	if (_modrootloaded) {
35590Sstevel@tonic-gate 		struct kobjopen_tctl *ltp = kobjopen_alloc(filename);
35600Sstevel@tonic-gate 		int Errno;
35610Sstevel@tonic-gate 
35620Sstevel@tonic-gate 		/*
35630Sstevel@tonic-gate 		 * Hand off the open to a thread who has a
35640Sstevel@tonic-gate 		 * stack size capable handling the request.
35650Sstevel@tonic-gate 		 */
35660Sstevel@tonic-gate 		if (curthread != &t0) {
35670Sstevel@tonic-gate 			(void) thread_create(NULL, DEFAULTSTKSZ * 2,
35680Sstevel@tonic-gate 			    kobjopen_thread, ltp, 0, &p0, TS_RUN, maxclsyspri);
35690Sstevel@tonic-gate 			sema_p(&ltp->sema);
35700Sstevel@tonic-gate 			Errno = ltp->Errno;
35710Sstevel@tonic-gate 			vp = ltp->vp;
35720Sstevel@tonic-gate 		} else {
35730Sstevel@tonic-gate 			/*
35740Sstevel@tonic-gate 			 * 1098067: module creds should not be those of the
35750Sstevel@tonic-gate 			 * caller
35760Sstevel@tonic-gate 			 */
35770Sstevel@tonic-gate 			cred_t *saved_cred = curthread->t_cred;
35780Sstevel@tonic-gate 			curthread->t_cred = kcred;
35791544Seschrock 			Errno = vn_openat(filename, UIO_SYSSPACE, FREAD, 0, &vp,
3580*5331Samw 			    0, 0, rootdir, -1);
35810Sstevel@tonic-gate 			curthread->t_cred = saved_cred;
35820Sstevel@tonic-gate 		}
35830Sstevel@tonic-gate 		kobjopen_free(ltp);
35840Sstevel@tonic-gate 
35850Sstevel@tonic-gate 		if (Errno) {
35860Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_ERRMSG) {
35870Sstevel@tonic-gate 				_kobj_printf(ops,
35880Sstevel@tonic-gate 				    "kobj_open: vn_open of %s fails, ",
35890Sstevel@tonic-gate 				    filename);
35900Sstevel@tonic-gate 				_kobj_printf(ops, "Errno = %d\n", Errno);
35910Sstevel@tonic-gate 			}
35920Sstevel@tonic-gate 			return (-1);
35930Sstevel@tonic-gate 		} else {
35940Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_ERRMSG) {
35950Sstevel@tonic-gate 				_kobj_printf(ops, "kobj_open: '%s'", filename);
35960Sstevel@tonic-gate 				_kobj_printf(ops, " vp = %p\n", vp);
35970Sstevel@tonic-gate 			}
35980Sstevel@tonic-gate 			return ((intptr_t)vp);
35990Sstevel@tonic-gate 		}
36000Sstevel@tonic-gate 	} else {
36010Sstevel@tonic-gate 		fd = kobj_boot_open(filename, 0);
36020Sstevel@tonic-gate 
36030Sstevel@tonic-gate 		if (_moddebug & MODDEBUG_ERRMSG) {
36040Sstevel@tonic-gate 			if (fd < 0)
36050Sstevel@tonic-gate 				_kobj_printf(ops,
36060Sstevel@tonic-gate 				    "kobj_open: can't open %s\n", filename);
36070Sstevel@tonic-gate 			else {
36080Sstevel@tonic-gate 				_kobj_printf(ops, "kobj_open: '%s'", filename);
36090Sstevel@tonic-gate 				_kobj_printf(ops, " descr = 0x%x\n", fd);
36100Sstevel@tonic-gate 			}
36110Sstevel@tonic-gate 		}
36120Sstevel@tonic-gate 		return ((intptr_t)fd);
36130Sstevel@tonic-gate 	}
36140Sstevel@tonic-gate }
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate /*
36170Sstevel@tonic-gate  * Calls to kobj_open() are handled off to this routine as a separate thread.
36180Sstevel@tonic-gate  */
36190Sstevel@tonic-gate static void
36200Sstevel@tonic-gate kobjopen_thread(struct kobjopen_tctl *ltp)
36210Sstevel@tonic-gate {
36220Sstevel@tonic-gate 	kmutex_t	cpr_lk;
36230Sstevel@tonic-gate 	callb_cpr_t	cpr_i;
36240Sstevel@tonic-gate 
36250Sstevel@tonic-gate 	mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
36260Sstevel@tonic-gate 	CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "kobjopen");
36270Sstevel@tonic-gate 	ltp->Errno = vn_open(ltp->name, UIO_SYSSPACE, FREAD, 0, &(ltp->vp),
36283912Slling 	    0, 0);
36290Sstevel@tonic-gate 	sema_v(&ltp->sema);
36300Sstevel@tonic-gate 	mutex_enter(&cpr_lk);
36310Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cpr_i);
36320Sstevel@tonic-gate 	mutex_destroy(&cpr_lk);
36330Sstevel@tonic-gate 	thread_exit();
36340Sstevel@tonic-gate }
36350Sstevel@tonic-gate 
36360Sstevel@tonic-gate /*
36370Sstevel@tonic-gate  * allocate and initialize a kobjopen thread structure
36380Sstevel@tonic-gate  */
36390Sstevel@tonic-gate static struct kobjopen_tctl *
36400Sstevel@tonic-gate kobjopen_alloc(char *filename)
36410Sstevel@tonic-gate {
36420Sstevel@tonic-gate 	struct kobjopen_tctl *ltp = kmem_zalloc(sizeof (*ltp), KM_SLEEP);
36430Sstevel@tonic-gate 
36440Sstevel@tonic-gate 	ASSERT(filename != NULL);
36450Sstevel@tonic-gate 
36460Sstevel@tonic-gate 	ltp->name = kmem_alloc(strlen(filename) + 1, KM_SLEEP);
36470Sstevel@tonic-gate 	bcopy(filename, ltp->name, strlen(filename) + 1);
36480Sstevel@tonic-gate 	sema_init(&ltp->sema, 0, NULL, SEMA_DEFAULT, NULL);
36490Sstevel@tonic-gate 	return (ltp);
36500Sstevel@tonic-gate }
36510Sstevel@tonic-gate 
36520Sstevel@tonic-gate /*
36530Sstevel@tonic-gate  * free a kobjopen thread control structure
36540Sstevel@tonic-gate  */
36550Sstevel@tonic-gate static void
36560Sstevel@tonic-gate kobjopen_free(struct kobjopen_tctl *ltp)
36570Sstevel@tonic-gate {
36580Sstevel@tonic-gate 	sema_destroy(&ltp->sema);
36590Sstevel@tonic-gate 	kmem_free(ltp->name, strlen(ltp->name) + 1);
36600Sstevel@tonic-gate 	kmem_free(ltp, sizeof (*ltp));
36610Sstevel@tonic-gate }
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate int
36640Sstevel@tonic-gate kobj_read(intptr_t descr, char *buf, unsigned size, unsigned offset)
36650Sstevel@tonic-gate {
36660Sstevel@tonic-gate 	int stat;
36670Sstevel@tonic-gate 	ssize_t resid;
36680Sstevel@tonic-gate 
36690Sstevel@tonic-gate 	if (_modrootloaded) {
36700Sstevel@tonic-gate 		if ((stat = vn_rdwr(UIO_READ, (struct vnode *)descr, buf, size,
36710Sstevel@tonic-gate 		    (offset_t)offset, UIO_SYSSPACE, 0, (rlim64_t)0, CRED(),
36720Sstevel@tonic-gate 		    &resid)) != 0) {
36730Sstevel@tonic-gate 			_kobj_printf(ops,
36740Sstevel@tonic-gate 			    "vn_rdwr failed with error 0x%x\n", stat);
36750Sstevel@tonic-gate 			return (-1);
36760Sstevel@tonic-gate 		}
36770Sstevel@tonic-gate 		return (size - resid);
36780Sstevel@tonic-gate 	} else {
36790Sstevel@tonic-gate 		int count = 0;
36800Sstevel@tonic-gate 
36810Sstevel@tonic-gate 		if (kobj_boot_seek((int)descr, (off_t)0, offset) != 0) {
36820Sstevel@tonic-gate 			_kobj_printf(ops,
36830Sstevel@tonic-gate 			    "kobj_read: seek 0x%x failed\n", offset);
36840Sstevel@tonic-gate 			return (-1);
36850Sstevel@tonic-gate 		}
36860Sstevel@tonic-gate 
36870Sstevel@tonic-gate 		count = kobj_boot_read((int)descr, buf, size);
36880Sstevel@tonic-gate 		if (count < size) {
36890Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_ERRMSG) {
36900Sstevel@tonic-gate 				_kobj_printf(ops,
36910Sstevel@tonic-gate 				    "kobj_read: req %d bytes, ", size);
36920Sstevel@tonic-gate 				_kobj_printf(ops, "got %d\n", count);
36930Sstevel@tonic-gate 			}
36940Sstevel@tonic-gate 		}
36950Sstevel@tonic-gate 		return (count);
36960Sstevel@tonic-gate 	}
36970Sstevel@tonic-gate }
36980Sstevel@tonic-gate 
36990Sstevel@tonic-gate void
37000Sstevel@tonic-gate kobj_close(intptr_t descr)
37010Sstevel@tonic-gate {
37020Sstevel@tonic-gate 	if (_moddebug & MODDEBUG_ERRMSG)
37030Sstevel@tonic-gate 		_kobj_printf(ops, "kobj_close: 0x%lx\n", descr);
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 	if (_modrootloaded) {
37060Sstevel@tonic-gate 		struct vnode *vp = (struct vnode *)descr;
3707*5331Samw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
37080Sstevel@tonic-gate 		VN_RELE(vp);
37090Sstevel@tonic-gate 	} else
37100Sstevel@tonic-gate 		(void) kobj_boot_close((int)descr);
37110Sstevel@tonic-gate }
37120Sstevel@tonic-gate 
37131544Seschrock int
37141544Seschrock kobj_fstat(intptr_t descr, struct bootstat *buf)
37151544Seschrock {
37161544Seschrock 	if (buf == NULL)
37171544Seschrock 		return (-1);
37181544Seschrock 
37191544Seschrock 	if (_modrootloaded) {
37201544Seschrock 		vattr_t vattr;
37211544Seschrock 		struct vnode *vp = (struct vnode *)descr;
3722*5331Samw 		if (VOP_GETATTR(vp, &vattr, 0, kcred, NULL) != 0)
37231544Seschrock 			return (-1);
37241544Seschrock 
37251544Seschrock 		/*
37261544Seschrock 		 * The vattr and bootstat structures are similar, but not
37271544Seschrock 		 * identical.  We do our best to fill in the bootstat structure
37281544Seschrock 		 * from the contents of vattr (transfering only the ones that
37291544Seschrock 		 * are obvious.
37301544Seschrock 		 */
37311544Seschrock 
37321544Seschrock 		buf->st_mode = (uint32_t)vattr.va_mode;
37331544Seschrock 		buf->st_nlink = (uint32_t)vattr.va_nlink;
37341544Seschrock 		buf->st_uid = (int32_t)vattr.va_uid;
37351544Seschrock 		buf->st_gid = (int32_t)vattr.va_gid;
37361544Seschrock 		buf->st_rdev = (uint64_t)vattr.va_rdev;
37371544Seschrock 		buf->st_size = (uint64_t)vattr.va_size;
37381544Seschrock 		buf->st_atim.tv_sec = (int64_t)vattr.va_atime.tv_sec;
37391544Seschrock 		buf->st_atim.tv_nsec = (int64_t)vattr.va_atime.tv_nsec;
37401544Seschrock 		buf->st_mtim.tv_sec = (int64_t)vattr.va_mtime.tv_sec;
37411544Seschrock 		buf->st_mtim.tv_nsec = (int64_t)vattr.va_mtime.tv_nsec;
37421544Seschrock 		buf->st_ctim.tv_sec = (int64_t)vattr.va_ctime.tv_sec;
37431544Seschrock 		buf->st_ctim.tv_nsec = (int64_t)vattr.va_ctime.tv_nsec;
37441544Seschrock 		buf->st_blksize = (int32_t)vattr.va_blksize;
37451544Seschrock 		buf->st_blocks = (int64_t)vattr.va_nblocks;
37461544Seschrock 
37471544Seschrock 		return (0);
37481544Seschrock 	}
37491544Seschrock 
37501544Seschrock 	return (kobj_boot_fstat((int)descr, buf));
37511544Seschrock }
37521544Seschrock 
37531544Seschrock 
37540Sstevel@tonic-gate struct _buf *
37550Sstevel@tonic-gate kobj_open_file(char *name)
37560Sstevel@tonic-gate {
37570Sstevel@tonic-gate 	struct _buf *file;
37580Sstevel@tonic-gate 	intptr_t fd;
37590Sstevel@tonic-gate 
37600Sstevel@tonic-gate 	if ((fd = kobj_open(name)) == -1) {
37610Sstevel@tonic-gate 		return ((struct _buf *)-1);
37620Sstevel@tonic-gate 	}
37630Sstevel@tonic-gate 
37640Sstevel@tonic-gate 	file = kobj_zalloc(sizeof (struct _buf), KM_WAIT|KM_TMP);
37650Sstevel@tonic-gate 	file->_fd = fd;
37660Sstevel@tonic-gate 	file->_name = kobj_alloc(strlen(name)+1, KM_WAIT|KM_TMP);
37670Sstevel@tonic-gate 	file->_base = kobj_zalloc(MAXBSIZE, KM_WAIT|KM_TMP);
37680Sstevel@tonic-gate 	file->_cnt = file->_size = file->_off = 0;
37690Sstevel@tonic-gate 	file->_ln = 1;
37700Sstevel@tonic-gate 	file->_ptr = file->_base;
37710Sstevel@tonic-gate 	(void) strcpy(file->_name, name);
37720Sstevel@tonic-gate 	return (file);
37730Sstevel@tonic-gate }
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate void
37760Sstevel@tonic-gate kobj_close_file(struct _buf *file)
37770Sstevel@tonic-gate {
37780Sstevel@tonic-gate 	kobj_close(file->_fd);
37790Sstevel@tonic-gate 	kobj_free(file->_base, MAXBSIZE);
37800Sstevel@tonic-gate 	kobj_free(file->_name, strlen(file->_name)+1);
37810Sstevel@tonic-gate 	kobj_free(file, sizeof (struct _buf));
37820Sstevel@tonic-gate }
37830Sstevel@tonic-gate 
37840Sstevel@tonic-gate int
37850Sstevel@tonic-gate kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
37860Sstevel@tonic-gate {
37870Sstevel@tonic-gate 	int b_size, c_size;
37880Sstevel@tonic-gate 	int b_off;	/* Offset into buffer for start of bcopy */
37890Sstevel@tonic-gate 	int count = 0;
37900Sstevel@tonic-gate 	int page_addr;
37910Sstevel@tonic-gate 
37920Sstevel@tonic-gate 	if (_moddebug & MODDEBUG_ERRMSG) {
37930Sstevel@tonic-gate 		_kobj_printf(ops, "kobj_read_file: size=%x,", size);
37940Sstevel@tonic-gate 		_kobj_printf(ops, " offset=%x at", off);
37950Sstevel@tonic-gate 		_kobj_printf(ops, " buf=%x\n", buf);
37960Sstevel@tonic-gate 	}
37970Sstevel@tonic-gate 
37980Sstevel@tonic-gate 	while (size) {
37990Sstevel@tonic-gate 		page_addr = F_PAGE(off);
38000Sstevel@tonic-gate 		b_size = file->_size;
38010Sstevel@tonic-gate 		/*
38020Sstevel@tonic-gate 		 * If we have the filesystem page the caller's referring to
38030Sstevel@tonic-gate 		 * and we have something in the buffer,
38040Sstevel@tonic-gate 		 * satisfy as much of the request from the buffer as we can.
38050Sstevel@tonic-gate 		 */
38060Sstevel@tonic-gate 		if (page_addr == file->_off && b_size > 0) {
38070Sstevel@tonic-gate 			b_off = B_OFFSET(off);
38080Sstevel@tonic-gate 			c_size = b_size - b_off;
38090Sstevel@tonic-gate 			/*
38100Sstevel@tonic-gate 			 * If there's nothing to copy, we're at EOF.
38110Sstevel@tonic-gate 			 */
38120Sstevel@tonic-gate 			if (c_size <= 0)
38130Sstevel@tonic-gate 				break;
38140Sstevel@tonic-gate 			if (c_size > size)
38150Sstevel@tonic-gate 				c_size = size;
38160Sstevel@tonic-gate 			if (buf) {
38170Sstevel@tonic-gate 				if (_moddebug & MODDEBUG_ERRMSG)
38180Sstevel@tonic-gate 					_kobj_printf(ops, "copying %x bytes\n",
38190Sstevel@tonic-gate 					    c_size);
38200Sstevel@tonic-gate 				bcopy(file->_base+b_off, buf, c_size);
38210Sstevel@tonic-gate 				size -= c_size;
38220Sstevel@tonic-gate 				off += c_size;
38230Sstevel@tonic-gate 				buf += c_size;
38240Sstevel@tonic-gate 				count += c_size;
38250Sstevel@tonic-gate 			} else {
38260Sstevel@tonic-gate 				_kobj_printf(ops, "kobj_read: system error");
38270Sstevel@tonic-gate 				count = -1;
38280Sstevel@tonic-gate 				break;
38290Sstevel@tonic-gate 			}
38300Sstevel@tonic-gate 		} else {
38310Sstevel@tonic-gate 			/*
38320Sstevel@tonic-gate 			 * If the caller's offset is page aligned and
38330Sstevel@tonic-gate 			 * the caller want's at least a filesystem page and
38340Sstevel@tonic-gate 			 * the caller provided a buffer,
38350Sstevel@tonic-gate 			 * read directly into the caller's buffer.
38360Sstevel@tonic-gate 			 */
38370Sstevel@tonic-gate 			if (page_addr == off &&
38380Sstevel@tonic-gate 			    (c_size = F_PAGE(size)) && buf) {
38390Sstevel@tonic-gate 				c_size = kobj_read(file->_fd, buf, c_size,
38403912Slling 				    page_addr);
38410Sstevel@tonic-gate 				if (c_size < 0) {
38420Sstevel@tonic-gate 					count = -1;
38430Sstevel@tonic-gate 					break;
38440Sstevel@tonic-gate 				}
38450Sstevel@tonic-gate 				count += c_size;
38460Sstevel@tonic-gate 				if (c_size != F_PAGE(size))
38470Sstevel@tonic-gate 					break;
38480Sstevel@tonic-gate 				size -= c_size;
38490Sstevel@tonic-gate 				off += c_size;
38500Sstevel@tonic-gate 				buf += c_size;
38510Sstevel@tonic-gate 			/*
38520Sstevel@tonic-gate 			 * Otherwise, read into our buffer and copy next time
38530Sstevel@tonic-gate 			 * around the loop.
38540Sstevel@tonic-gate 			 */
38550Sstevel@tonic-gate 			} else {
38560Sstevel@tonic-gate 				file->_off = page_addr;
38570Sstevel@tonic-gate 				c_size = kobj_read(file->_fd, file->_base,
38583912Slling 				    MAXBSIZE, page_addr);
38590Sstevel@tonic-gate 				file->_ptr = file->_base;
38600Sstevel@tonic-gate 				file->_cnt = c_size;
38610Sstevel@tonic-gate 				file->_size = c_size;
38620Sstevel@tonic-gate 				/*
38630Sstevel@tonic-gate 				 * If a _filbuf call or nothing read, break.
38640Sstevel@tonic-gate 				 */
38650Sstevel@tonic-gate 				if (buf == NULL || c_size <= 0) {
38660Sstevel@tonic-gate 					count = c_size;
38670Sstevel@tonic-gate 					break;
38680Sstevel@tonic-gate 				}
38690Sstevel@tonic-gate 			}
38700Sstevel@tonic-gate 			if (_moddebug & MODDEBUG_ERRMSG)
38710Sstevel@tonic-gate 				_kobj_printf(ops, "read %x bytes\n", c_size);
38720Sstevel@tonic-gate 		}
38730Sstevel@tonic-gate 	}
38740Sstevel@tonic-gate 	if (_moddebug & MODDEBUG_ERRMSG)
38750Sstevel@tonic-gate 		_kobj_printf(ops, "count = %x\n", count);
38760Sstevel@tonic-gate 
38770Sstevel@tonic-gate 	return (count);
38780Sstevel@tonic-gate }
38790Sstevel@tonic-gate 
38800Sstevel@tonic-gate int
38810Sstevel@tonic-gate kobj_filbuf(struct _buf *f)
38820Sstevel@tonic-gate {
38830Sstevel@tonic-gate 	if (kobj_read_file(f, NULL, MAXBSIZE, f->_off + f->_size) > 0)
38840Sstevel@tonic-gate 		return (kobj_getc(f));
38850Sstevel@tonic-gate 	return (-1);
38860Sstevel@tonic-gate }
38870Sstevel@tonic-gate 
38880Sstevel@tonic-gate void
38890Sstevel@tonic-gate kobj_free(void *address, size_t size)
38900Sstevel@tonic-gate {
38910Sstevel@tonic-gate 	if (standalone)
38920Sstevel@tonic-gate 		return;
38930Sstevel@tonic-gate 
38940Sstevel@tonic-gate 	kmem_free(address, size);
38950Sstevel@tonic-gate 	kobj_stat.nfree_calls++;
38960Sstevel@tonic-gate 	kobj_stat.nfree += size;
38970Sstevel@tonic-gate }
38980Sstevel@tonic-gate 
38990Sstevel@tonic-gate void *
39000Sstevel@tonic-gate kobj_zalloc(size_t size, int flag)
39010Sstevel@tonic-gate {
39020Sstevel@tonic-gate 	void *v;
39030Sstevel@tonic-gate 
39040Sstevel@tonic-gate 	if ((v = kobj_alloc(size, flag)) != 0) {
39050Sstevel@tonic-gate 		bzero(v, size);
39060Sstevel@tonic-gate 	}
39070Sstevel@tonic-gate 
39080Sstevel@tonic-gate 	return (v);
39090Sstevel@tonic-gate }
39100Sstevel@tonic-gate 
39110Sstevel@tonic-gate void *
39120Sstevel@tonic-gate kobj_alloc(size_t size, int flag)
39130Sstevel@tonic-gate {
39140Sstevel@tonic-gate 	/*
39150Sstevel@tonic-gate 	 * If we are running standalone in the
39160Sstevel@tonic-gate 	 * linker, we ask boot for memory.
39170Sstevel@tonic-gate 	 * Either it's temporary memory that we lose
39180Sstevel@tonic-gate 	 * once boot is mapped out or we allocate it
39190Sstevel@tonic-gate 	 * permanently using the dynamic data segment.
39200Sstevel@tonic-gate 	 */
39210Sstevel@tonic-gate 	if (standalone) {
39220Sstevel@tonic-gate #ifdef __sparc
39230Sstevel@tonic-gate 		if (flag & KM_TMP) {
39240Sstevel@tonic-gate 			return (kobj_tmp_alloc(size));
39250Sstevel@tonic-gate 		} else if (flag & KM_SCRATCH) {
39260Sstevel@tonic-gate 			void *buf = kobj_bs_alloc(size);
39270Sstevel@tonic-gate 
39280Sstevel@tonic-gate 			if (buf != NULL)
39290Sstevel@tonic-gate 				return (buf);
39300Sstevel@tonic-gate #ifdef	KOBJ_DEBUG
39310Sstevel@tonic-gate 			if (kobj_debug & D_DEBUG) {
39320Sstevel@tonic-gate 				_kobj_printf(ops, "krtld: failed scratch alloc "
39333446Smrj 				    "of %lu bytes -- falling back\n", size);
39340Sstevel@tonic-gate 			}
39350Sstevel@tonic-gate #endif
39360Sstevel@tonic-gate 		}
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate #else /* x86 */
39390Sstevel@tonic-gate 		if (flag & (KM_TMP | KM_SCRATCH))
39400Sstevel@tonic-gate 			return (BOP_ALLOC(ops, 0, size, MINALIGN));
39410Sstevel@tonic-gate #endif
39420Sstevel@tonic-gate 		return (kobj_segbrk(&_edata, size, MINALIGN, 0));
39430Sstevel@tonic-gate 	}
39440Sstevel@tonic-gate 
39450Sstevel@tonic-gate 	kobj_stat.nalloc_calls++;
39460Sstevel@tonic-gate 	kobj_stat.nalloc += size;
39470Sstevel@tonic-gate 
39480Sstevel@tonic-gate 	return (kmem_alloc(size, (flag & KM_NOWAIT) ? KM_NOSLEEP : KM_SLEEP));
39490Sstevel@tonic-gate }
39500Sstevel@tonic-gate 
39510Sstevel@tonic-gate /*
39520Sstevel@tonic-gate  * Allow the "mod" system to sync up with the work
39530Sstevel@tonic-gate  * already done by kobj during the initial loading
39540Sstevel@tonic-gate  * of the kernel.  This also gives us a chance
39550Sstevel@tonic-gate  * to reallocate memory that belongs to boot.
39560Sstevel@tonic-gate  */
39570Sstevel@tonic-gate void
39580Sstevel@tonic-gate kobj_sync(void)
39590Sstevel@tonic-gate {
39600Sstevel@tonic-gate 	struct modctl_list *lp, **lpp;
39610Sstevel@tonic-gate 
39620Sstevel@tonic-gate 	/*
39633446Smrj 	 * The module path can be set in /etc/system via 'moddir' commands
39640Sstevel@tonic-gate 	 */
39650Sstevel@tonic-gate 	if (default_path != NULL)
39663446Smrj 		kobj_module_path = default_path;
39670Sstevel@tonic-gate 	else
39683446Smrj 		default_path = kobj_module_path;
39690Sstevel@tonic-gate 
39700Sstevel@tonic-gate 	ksyms_arena = vmem_create("ksyms", NULL, 0, sizeof (uint64_t),
39710Sstevel@tonic-gate 	    segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
39720Sstevel@tonic-gate 
39730Sstevel@tonic-gate 	ctf_arena = vmem_create("ctf", NULL, 0, sizeof (uint_t),
39740Sstevel@tonic-gate 	    segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
39750Sstevel@tonic-gate 
39760Sstevel@tonic-gate 	/*
39770Sstevel@tonic-gate 	 * Move symbol tables from boot memory to ksyms_arena.
39780Sstevel@tonic-gate 	 */
39790Sstevel@tonic-gate 	for (lpp = kobj_linkmaps; *lpp != NULL; lpp++) {
39800Sstevel@tonic-gate 		for (lp = *lpp; lp != NULL; lp = lp->modl_next)
39810Sstevel@tonic-gate 			kobj_export_module(mod(lp));
39820Sstevel@tonic-gate 	}
39830Sstevel@tonic-gate }
39840Sstevel@tonic-gate 
39850Sstevel@tonic-gate caddr_t
39860Sstevel@tonic-gate kobj_segbrk(caddr_t *spp, size_t size, size_t align, caddr_t limit)
39870Sstevel@tonic-gate {
39880Sstevel@tonic-gate 	uintptr_t va, pva;
39890Sstevel@tonic-gate 	size_t alloc_pgsz = kobj_mmu_pagesize;
39900Sstevel@tonic-gate 	size_t alloc_align = BO_NO_ALIGN;
39910Sstevel@tonic-gate 	size_t alloc_size;
39920Sstevel@tonic-gate 
39930Sstevel@tonic-gate 	/*
39940Sstevel@tonic-gate 	 * If we are using "large" mappings for the kernel,
39950Sstevel@tonic-gate 	 * request aligned memory from boot using the
39960Sstevel@tonic-gate 	 * "large" pagesize.
39970Sstevel@tonic-gate 	 */
39980Sstevel@tonic-gate 	if (lg_pagesize) {
39990Sstevel@tonic-gate 		alloc_align = lg_pagesize;
40000Sstevel@tonic-gate 		alloc_pgsz = lg_pagesize;
40010Sstevel@tonic-gate 	}
40020Sstevel@tonic-gate 	va = ALIGN((uintptr_t)*spp, align);
40030Sstevel@tonic-gate 	pva = P2ROUNDUP((uintptr_t)*spp, alloc_pgsz);
40040Sstevel@tonic-gate 	/*
40050Sstevel@tonic-gate 	 * Need more pages?
40060Sstevel@tonic-gate 	 */
40070Sstevel@tonic-gate 	if (va + size > pva) {
40083446Smrj 		uintptr_t npva;
40093446Smrj 
40100Sstevel@tonic-gate 		alloc_size = P2ROUNDUP(size - (pva - va), alloc_pgsz);
40110Sstevel@tonic-gate 		/*
40120Sstevel@tonic-gate 		 * Check for overlapping segments.
40130Sstevel@tonic-gate 		 */
40143446Smrj 		if (limit && limit <= *spp + alloc_size) {
40150Sstevel@tonic-gate 			return ((caddr_t)0);
40163446Smrj 		}
40173446Smrj 
40183446Smrj 		npva = (uintptr_t)BOP_ALLOC(ops, (caddr_t)pva,
40193912Slling 		    alloc_size, alloc_align);
40203446Smrj 
40213446Smrj 		if (npva == NULL) {
40223446Smrj 			_kobj_printf(ops, "BOP_ALLOC failed, 0x%lx bytes",
40230Sstevel@tonic-gate 			    alloc_size);
40243446Smrj 			_kobj_printf(ops, " aligned %lx", alloc_align);
40250Sstevel@tonic-gate 			_kobj_printf(ops, " at 0x%lx\n", pva);
40263446Smrj 			return (NULL);
40270Sstevel@tonic-gate 		}
40280Sstevel@tonic-gate 	}
40290Sstevel@tonic-gate 	*spp = (caddr_t)(va + size);
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 	return ((caddr_t)va);
40320Sstevel@tonic-gate }
40330Sstevel@tonic-gate 
40340Sstevel@tonic-gate /*
40350Sstevel@tonic-gate  * Calculate the number of output hash buckets.
40360Sstevel@tonic-gate  * We use the next prime larger than n / 4,
40370Sstevel@tonic-gate  * so the average hash chain is about 4 entries.
40380Sstevel@tonic-gate  * More buckets would just be a waste of memory.
40390Sstevel@tonic-gate  */
40400Sstevel@tonic-gate uint_t
40410Sstevel@tonic-gate kobj_gethashsize(uint_t n)
40420Sstevel@tonic-gate {
40430Sstevel@tonic-gate 	int f;
40440Sstevel@tonic-gate 	int hsize = MAX(n / 4, 2);
40450Sstevel@tonic-gate 
40460Sstevel@tonic-gate 	for (f = 2; f * f <= hsize; f++)
40470Sstevel@tonic-gate 		if (hsize % f == 0)
40480Sstevel@tonic-gate 			hsize += f = 1;
40490Sstevel@tonic-gate 
40500Sstevel@tonic-gate 	return (hsize);
40510Sstevel@tonic-gate }
40520Sstevel@tonic-gate 
40533912Slling /*
40543912Slling  * Get the file size.
40553912Slling  *
40563912Slling  * Before root is mounted, files are compressed in the boot_archive ramdisk
40573912Slling  * (in the memory). kobj_fstat would return the compressed file size.
40583912Slling  * In order to get the uncompressed file size, read the file to the end and
40593912Slling  * count its size.
40603912Slling  */
40613912Slling int
40623912Slling kobj_get_filesize(struct _buf *file, uint64_t *size)
40633912Slling {
40643912Slling 	if (_modrootloaded) {
40653912Slling 		struct bootstat bst;
40663912Slling 
40673912Slling 		if (kobj_fstat(file->_fd, &bst) != 0)
40683912Slling 			return (EIO);
40693912Slling 		*size = bst.st_size;
40703912Slling 	} else {
40713912Slling 		char *buf;
40723912Slling 		int count;
40733912Slling 		uint64_t offset = 0;
40743912Slling 
40753912Slling 		buf = kmem_alloc(MAXBSIZE, KM_SLEEP);
40763912Slling 		do {
40773912Slling 			count = kobj_read_file(file, buf, MAXBSIZE, offset);
40783912Slling 			if (count < 0) {
40793912Slling 				kmem_free(buf, MAXBSIZE);
40803912Slling 				return (EIO);
40813912Slling 			}
40823912Slling 			offset += count;
40833912Slling 		} while (count == MAXBSIZE);
40843912Slling 		kmem_free(buf, MAXBSIZE);
40853912Slling 
40863912Slling 		*size = offset;
40873912Slling 	}
40883912Slling 
40893912Slling 	return (0);
40903912Slling }
40913912Slling 
40920Sstevel@tonic-gate static char *
40930Sstevel@tonic-gate basename(char *s)
40940Sstevel@tonic-gate {
40950Sstevel@tonic-gate 	char *p, *q;
40960Sstevel@tonic-gate 
40970Sstevel@tonic-gate 	q = NULL;
40980Sstevel@tonic-gate 	p = s;
40990Sstevel@tonic-gate 	do {
41000Sstevel@tonic-gate 		if (*p == '/')
41010Sstevel@tonic-gate 			q = p;
41020Sstevel@tonic-gate 	} while (*p++);
41030Sstevel@tonic-gate 	return (q ? q + 1 : s);
41040Sstevel@tonic-gate }
41050Sstevel@tonic-gate 
41060Sstevel@tonic-gate /*ARGSUSED*/
41070Sstevel@tonic-gate static void
41080Sstevel@tonic-gate kprintf(void *op, const char *fmt, ...)
41090Sstevel@tonic-gate {
41100Sstevel@tonic-gate 	va_list adx;
41110Sstevel@tonic-gate 
41120Sstevel@tonic-gate 	va_start(adx, fmt);
41130Sstevel@tonic-gate 	vprintf(fmt, adx);
41140Sstevel@tonic-gate 	va_end(adx);
41150Sstevel@tonic-gate }
41160Sstevel@tonic-gate 
41170Sstevel@tonic-gate void
41180Sstevel@tonic-gate kobj_stat_get(kobj_stat_t *kp)
41190Sstevel@tonic-gate {
41200Sstevel@tonic-gate 	*kp = kobj_stat;
41210Sstevel@tonic-gate }
41220Sstevel@tonic-gate 
41230Sstevel@tonic-gate int
41240Sstevel@tonic-gate kobj_getpagesize()
41250Sstevel@tonic-gate {
41260Sstevel@tonic-gate 	return (lg_pagesize);
41270Sstevel@tonic-gate }
41280Sstevel@tonic-gate 
41290Sstevel@tonic-gate void
41300Sstevel@tonic-gate kobj_textwin_alloc(struct module *mp)
41310Sstevel@tonic-gate {
41320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&mod_lock));
41330Sstevel@tonic-gate 
41340Sstevel@tonic-gate 	if (mp->textwin != NULL)
41350Sstevel@tonic-gate 		return;
41360Sstevel@tonic-gate 
41370Sstevel@tonic-gate 	/*
41380Sstevel@tonic-gate 	 * If the text is not contained in the heap, then it is not contained
41390Sstevel@tonic-gate 	 * by a writable mapping.  (Specifically, it's on the nucleus page.)
41400Sstevel@tonic-gate 	 * We allocate a read/write mapping for this module's text to allow
41410Sstevel@tonic-gate 	 * the text to be patched without calling hot_patch_kernel_text()
41420Sstevel@tonic-gate 	 * (which is quite slow).
41430Sstevel@tonic-gate 	 */
41440Sstevel@tonic-gate 	if (!vmem_contains(heaptext_arena, mp->text, mp->text_size)) {
41450Sstevel@tonic-gate 		uintptr_t text = (uintptr_t)mp->text;
41460Sstevel@tonic-gate 		uintptr_t size = (uintptr_t)mp->text_size;
41470Sstevel@tonic-gate 		uintptr_t i;
41480Sstevel@tonic-gate 		caddr_t va;
41490Sstevel@tonic-gate 		size_t sz = ((text + size + PAGESIZE - 1) & PAGEMASK) -
41500Sstevel@tonic-gate 		    (text & PAGEMASK);
41510Sstevel@tonic-gate 
41520Sstevel@tonic-gate 		va = mp->textwin_base = vmem_alloc(heap_arena, sz, VM_SLEEP);
41530Sstevel@tonic-gate 
41540Sstevel@tonic-gate 		for (i = text & PAGEMASK; i < text + size; i += PAGESIZE) {
41550Sstevel@tonic-gate 			hat_devload(kas.a_hat, va, PAGESIZE,
41560Sstevel@tonic-gate 			    hat_getpfnum(kas.a_hat, (caddr_t)i),
41570Sstevel@tonic-gate 			    PROT_READ | PROT_WRITE,
41580Sstevel@tonic-gate 			    HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
41590Sstevel@tonic-gate 			va += PAGESIZE;
41600Sstevel@tonic-gate 		}
41610Sstevel@tonic-gate 
41620Sstevel@tonic-gate 		mp->textwin = mp->textwin_base + (text & PAGEOFFSET);
41630Sstevel@tonic-gate 	} else {
41640Sstevel@tonic-gate 		mp->textwin = mp->text;
41650Sstevel@tonic-gate 	}
41660Sstevel@tonic-gate }
41670Sstevel@tonic-gate 
41680Sstevel@tonic-gate void
41690Sstevel@tonic-gate kobj_textwin_free(struct module *mp)
41700Sstevel@tonic-gate {
41710Sstevel@tonic-gate 	uintptr_t text = (uintptr_t)mp->text;
41720Sstevel@tonic-gate 	uintptr_t tsize = (uintptr_t)mp->text_size;
41730Sstevel@tonic-gate 	size_t size = (((text + tsize + PAGESIZE - 1) & PAGEMASK) -
41740Sstevel@tonic-gate 	    (text & PAGEMASK));
41750Sstevel@tonic-gate 
41760Sstevel@tonic-gate 	mp->textwin = NULL;
41770Sstevel@tonic-gate 
41780Sstevel@tonic-gate 	if (mp->textwin_base == NULL)
41790Sstevel@tonic-gate 		return;
41800Sstevel@tonic-gate 
41810Sstevel@tonic-gate 	hat_unload(kas.a_hat, mp->textwin_base, size, HAT_UNLOAD_UNLOCK);
41820Sstevel@tonic-gate 	vmem_free(heap_arena, mp->textwin_base, size);
41830Sstevel@tonic-gate 	mp->textwin_base = NULL;
41840Sstevel@tonic-gate }
41850Sstevel@tonic-gate 
41860Sstevel@tonic-gate static char *
41870Sstevel@tonic-gate find_libmacro(char *name)
41880Sstevel@tonic-gate {
41890Sstevel@tonic-gate 	int lmi;
41900Sstevel@tonic-gate 
41910Sstevel@tonic-gate 	for (lmi = 0; lmi < NLIBMACROS; lmi++) {
41920Sstevel@tonic-gate 		if (strcmp(name, libmacros[lmi].lmi_macroname) == 0)
41930Sstevel@tonic-gate 			return (libmacros[lmi].lmi_list);
41940Sstevel@tonic-gate 	}
41950Sstevel@tonic-gate 	return (NULL);
41960Sstevel@tonic-gate }
41970Sstevel@tonic-gate 
41980Sstevel@tonic-gate /*
41990Sstevel@tonic-gate  * Check for $MACRO in tail (string to expand) and expand it in path at pathend
42000Sstevel@tonic-gate  * returns path if successful, else NULL
42010Sstevel@tonic-gate  * Support multiple $MACROs expansion and the first valid path will be returned
42020Sstevel@tonic-gate  * Caller's responsibility to provide enough space in path to expand
42030Sstevel@tonic-gate  */
42040Sstevel@tonic-gate char *
42050Sstevel@tonic-gate expand_libmacro(char *tail, char *path, char *pathend)
42060Sstevel@tonic-gate {
42070Sstevel@tonic-gate 	char c, *p, *p1, *p2, *path2, *endp;
42080Sstevel@tonic-gate 	int diff, lmi, macrolen, valid_macro, more_macro;
42090Sstevel@tonic-gate 	struct _buf *file;
42100Sstevel@tonic-gate 
42110Sstevel@tonic-gate 	/*
42120Sstevel@tonic-gate 	 * check for $MACROS between nulls or slashes
42130Sstevel@tonic-gate 	 */
42140Sstevel@tonic-gate 	p = strchr(tail, '$');
42150Sstevel@tonic-gate 	if (p == NULL)
42160Sstevel@tonic-gate 		return (NULL);
42170Sstevel@tonic-gate 	for (lmi = 0; lmi < NLIBMACROS; lmi++) {
42180Sstevel@tonic-gate 		macrolen = libmacros[lmi].lmi_macrolen;
42190Sstevel@tonic-gate 		if (strncmp(p + 1, libmacros[lmi].lmi_macroname, macrolen) == 0)
42200Sstevel@tonic-gate 			break;
42210Sstevel@tonic-gate 	}
42220Sstevel@tonic-gate 
42230Sstevel@tonic-gate 	valid_macro = 0;
42240Sstevel@tonic-gate 	if (lmi < NLIBMACROS) {
42250Sstevel@tonic-gate 		/*
42260Sstevel@tonic-gate 		 * The following checks are used to restrict expansion of
42270Sstevel@tonic-gate 		 * macros to those that form a full directory/file name
42280Sstevel@tonic-gate 		 * and to keep the behavior same as before.  If this
42290Sstevel@tonic-gate 		 * restriction is removed or no longer valid in the future,
42300Sstevel@tonic-gate 		 * the checks below can be deleted.
42310Sstevel@tonic-gate 		 */
42320Sstevel@tonic-gate 		if ((p == tail) || (*(p - 1) == '/')) {
42330Sstevel@tonic-gate 			c = *(p + macrolen + 1);
42340Sstevel@tonic-gate 			if (c == '/' || c == '\0')
42350Sstevel@tonic-gate 				valid_macro = 1;
42360Sstevel@tonic-gate 		}
42370Sstevel@tonic-gate 	}
42380Sstevel@tonic-gate 
42390Sstevel@tonic-gate 	if (!valid_macro) {
42400Sstevel@tonic-gate 		p2 = strchr(p, '/');
42410Sstevel@tonic-gate 		/*
42420Sstevel@tonic-gate 		 * if no more macro to expand, then just copy whatever left
42430Sstevel@tonic-gate 		 * and check whether it exists
42440Sstevel@tonic-gate 		 */
42450Sstevel@tonic-gate 		if (p2 == NULL || strchr(p2, '$') == NULL) {
42460Sstevel@tonic-gate 			(void) strcpy(pathend, tail);
42470Sstevel@tonic-gate 			if ((file = kobj_open_path(path, 1, 1)) !=
42480Sstevel@tonic-gate 			    (struct _buf *)-1) {
42490Sstevel@tonic-gate 				kobj_close_file(file);
42500Sstevel@tonic-gate 				return (path);
42510Sstevel@tonic-gate 			} else
42520Sstevel@tonic-gate 				return (NULL);
42530Sstevel@tonic-gate 		} else {
42540Sstevel@tonic-gate 			/*
42550Sstevel@tonic-gate 			 * copy all chars before '/' and call expand_libmacro()
42560Sstevel@tonic-gate 			 * again
42570Sstevel@tonic-gate 			 */
42580Sstevel@tonic-gate 			diff = p2 - tail;
42590Sstevel@tonic-gate 			bcopy(tail, pathend, diff);
42600Sstevel@tonic-gate 			pathend += diff;
42610Sstevel@tonic-gate 			*(pathend) = '\0';
42620Sstevel@tonic-gate 			return (expand_libmacro(p2, path, pathend));
42630Sstevel@tonic-gate 		}
42640Sstevel@tonic-gate 	}
42650Sstevel@tonic-gate 
42660Sstevel@tonic-gate 	more_macro = 0;
42670Sstevel@tonic-gate 	if (c != '\0') {
42680Sstevel@tonic-gate 		endp = p + macrolen + 1;
42690Sstevel@tonic-gate 		if (strchr(endp, '$') != NULL)
42700Sstevel@tonic-gate 			more_macro = 1;
42710Sstevel@tonic-gate 	} else
42720Sstevel@tonic-gate 		endp = NULL;
42730Sstevel@tonic-gate 
42740Sstevel@tonic-gate 	/*
42750Sstevel@tonic-gate 	 * copy lmi_list and split it into components.
42760Sstevel@tonic-gate 	 * then put the part of tail before $MACRO into path
42770Sstevel@tonic-gate 	 * at pathend
42780Sstevel@tonic-gate 	 */
42790Sstevel@tonic-gate 	diff = p - tail;
42800Sstevel@tonic-gate 	if (diff > 0)
42810Sstevel@tonic-gate 		bcopy(tail, pathend, diff);
42820Sstevel@tonic-gate 	path2 = pathend + diff;
42830Sstevel@tonic-gate 	p1 = libmacros[lmi].lmi_list;
42840Sstevel@tonic-gate 	while (p1 && (*p1 != '\0')) {
42850Sstevel@tonic-gate 		p2 = strchr(p1, ':');
42860Sstevel@tonic-gate 		if (p2) {
42870Sstevel@tonic-gate 			diff = p2 - p1;
42880Sstevel@tonic-gate 			bcopy(p1, path2, diff);
42890Sstevel@tonic-gate 			*(path2 + diff) = '\0';
42900Sstevel@tonic-gate 		} else {
42910Sstevel@tonic-gate 			diff = strlen(p1);
42920Sstevel@tonic-gate 			bcopy(p1, path2, diff + 1);
42930Sstevel@tonic-gate 		}
42940Sstevel@tonic-gate 		/* copy endp only if there isn't any more macro to expand */
42950Sstevel@tonic-gate 		if (!more_macro && (endp != NULL))
42960Sstevel@tonic-gate 			(void) strcat(path2, endp);
42970Sstevel@tonic-gate 		file = kobj_open_path(path, 1, 1);
42980Sstevel@tonic-gate 		if (file != (struct _buf *)-1) {
42990Sstevel@tonic-gate 			kobj_close_file(file);
43000Sstevel@tonic-gate 			/*
43010Sstevel@tonic-gate 			 * if more macros to expand then call expand_libmacro(),
43020Sstevel@tonic-gate 			 * else return path which has the whole path
43030Sstevel@tonic-gate 			 */
43040Sstevel@tonic-gate 			if (!more_macro || (expand_libmacro(endp, path,
43050Sstevel@tonic-gate 			    path2 + diff) != NULL)) {
43060Sstevel@tonic-gate 				return (path);
43070Sstevel@tonic-gate 			}
43080Sstevel@tonic-gate 		}
43090Sstevel@tonic-gate 		if (p2)
43100Sstevel@tonic-gate 			p1 = ++p2;
43110Sstevel@tonic-gate 		else
43120Sstevel@tonic-gate 			return (NULL);
43130Sstevel@tonic-gate 	}
43140Sstevel@tonic-gate 	return (NULL);
43150Sstevel@tonic-gate }
43160Sstevel@tonic-gate 
43170Sstevel@tonic-gate static void
43180Sstevel@tonic-gate tnf_add_notifyunload(kobj_notify_f *fp)
43190Sstevel@tonic-gate {
43200Sstevel@tonic-gate 	kobj_notify_list_t *entry;
43210Sstevel@tonic-gate 
43220Sstevel@tonic-gate 	entry = kobj_alloc(sizeof (kobj_notify_list_t), KM_WAIT);
43230Sstevel@tonic-gate 	entry->kn_type = KOBJ_NOTIFY_MODUNLOADING;
43240Sstevel@tonic-gate 	entry->kn_func = fp;
43250Sstevel@tonic-gate 	(void) kobj_notify_add(entry);
43260Sstevel@tonic-gate }
43270Sstevel@tonic-gate 
43280Sstevel@tonic-gate /* ARGSUSED */
43290Sstevel@tonic-gate static void
43300Sstevel@tonic-gate tnf_unsplice_probes(unsigned int what, struct modctl *mod)
43310Sstevel@tonic-gate {
43320Sstevel@tonic-gate 	extern tnf_probe_control_t *__tnf_probe_list_head;
43330Sstevel@tonic-gate 	extern tnf_tag_data_t *__tnf_tag_list_head;
43340Sstevel@tonic-gate 	tnf_probe_control_t **p;
43350Sstevel@tonic-gate 	tnf_tag_data_t **q;
43360Sstevel@tonic-gate 	struct module *mp = mod->mod_mp;
43370Sstevel@tonic-gate 
43380Sstevel@tonic-gate 	if (!(mp->flags & KOBJ_TNF_PROBE))
43390Sstevel@tonic-gate 		return;
43400Sstevel@tonic-gate 
43410Sstevel@tonic-gate 	for (p = &__tnf_probe_list_head; *p; )
43420Sstevel@tonic-gate 		if (kobj_addrcheck(mp, (char *)*p) == 0)
43430Sstevel@tonic-gate 			*p = (*p)->next;
43440Sstevel@tonic-gate 		else
43450Sstevel@tonic-gate 			p = &(*p)->next;
43460Sstevel@tonic-gate 
43470Sstevel@tonic-gate 	for (q = &__tnf_tag_list_head; *q; )
43480Sstevel@tonic-gate 		if (kobj_addrcheck(mp, (char *)*q) == 0)
43490Sstevel@tonic-gate 			*q = (tnf_tag_data_t *)(*q)->tag_version;
43500Sstevel@tonic-gate 		else
43510Sstevel@tonic-gate 			q = (tnf_tag_data_t **)&(*q)->tag_version;
43520Sstevel@tonic-gate 
43530Sstevel@tonic-gate 	tnf_changed_probe_list = 1;
43540Sstevel@tonic-gate }
43550Sstevel@tonic-gate 
43560Sstevel@tonic-gate int
43570Sstevel@tonic-gate tnf_splice_probes(int boot_load, tnf_probe_control_t *plist,
43580Sstevel@tonic-gate     tnf_tag_data_t *tlist)
43590Sstevel@tonic-gate {
43600Sstevel@tonic-gate 	int result = 0;
43610Sstevel@tonic-gate 	static int add_notify = 1;
43620Sstevel@tonic-gate 
43630Sstevel@tonic-gate 	if (plist) {
43640Sstevel@tonic-gate 		tnf_probe_control_t *pl;
43650Sstevel@tonic-gate 
43660Sstevel@tonic-gate 		for (pl = plist; pl->next; )
43670Sstevel@tonic-gate 			pl = pl->next;
43680Sstevel@tonic-gate 
43690Sstevel@tonic-gate 		if (!boot_load)
43700Sstevel@tonic-gate 			mutex_enter(&mod_lock);
43710Sstevel@tonic-gate 		tnf_changed_probe_list = 1;
43720Sstevel@tonic-gate 		pl->next = __tnf_probe_list_head;
43730Sstevel@tonic-gate 		__tnf_probe_list_head = plist;
43740Sstevel@tonic-gate 		if (!boot_load)
43750Sstevel@tonic-gate 			mutex_exit(&mod_lock);
43760Sstevel@tonic-gate 		result = 1;
43770Sstevel@tonic-gate 	}
43780Sstevel@tonic-gate 
43790Sstevel@tonic-gate 	if (tlist) {
43800Sstevel@tonic-gate 		tnf_tag_data_t *tl;
43810Sstevel@tonic-gate 
43820Sstevel@tonic-gate 		for (tl = tlist; tl->tag_version; )
43830Sstevel@tonic-gate 			tl = (tnf_tag_data_t *)tl->tag_version;
43840Sstevel@tonic-gate 
43850Sstevel@tonic-gate 		if (!boot_load)
43860Sstevel@tonic-gate 			mutex_enter(&mod_lock);
43870Sstevel@tonic-gate 		tl->tag_version = (tnf_tag_version_t *)__tnf_tag_list_head;
43880Sstevel@tonic-gate 		__tnf_tag_list_head = tlist;
43890Sstevel@tonic-gate 		if (!boot_load)
43900Sstevel@tonic-gate 			mutex_exit(&mod_lock);
43910Sstevel@tonic-gate 		result = 1;
43920Sstevel@tonic-gate 	}
43930Sstevel@tonic-gate 	if (!boot_load && result && add_notify) {
43940Sstevel@tonic-gate 		tnf_add_notifyunload(tnf_unsplice_probes);
43950Sstevel@tonic-gate 		add_notify = 0;
43960Sstevel@tonic-gate 	}
43970Sstevel@tonic-gate 	return (result);
43980Sstevel@tonic-gate }
43990Sstevel@tonic-gate 
44000Sstevel@tonic-gate #if defined(__x86)
44010Sstevel@tonic-gate /*
44020Sstevel@tonic-gate  * This code is for the purpose of manually recording which files
44030Sstevel@tonic-gate  * needs to go into the boot archive on any given system.
44040Sstevel@tonic-gate  *
44050Sstevel@tonic-gate  * To enable the code, set kobj_file_bufsize in /etc/system
44060Sstevel@tonic-gate  * and reboot the system, then use mdb to look at kobj_file_buf.
44070Sstevel@tonic-gate  */
44080Sstevel@tonic-gate static void
44090Sstevel@tonic-gate kobj_record_file(char *filename)
44100Sstevel@tonic-gate {
44110Sstevel@tonic-gate 	extern char *kobj_file_buf;
44120Sstevel@tonic-gate 	extern int kobj_file_bufsize;
44130Sstevel@tonic-gate 	static char *buf;
44140Sstevel@tonic-gate 	static int size = 0;
44150Sstevel@tonic-gate 	int n;
44160Sstevel@tonic-gate 
44170Sstevel@tonic-gate 	if (standalone)		/* kernel symbol not available */
44180Sstevel@tonic-gate 		return;
44190Sstevel@tonic-gate 
44200Sstevel@tonic-gate 	if (kobj_file_bufsize == 0)	/* don't bother */
44210Sstevel@tonic-gate 		return;
44220Sstevel@tonic-gate 
44230Sstevel@tonic-gate 	if (kobj_file_buf == NULL) {	/* allocate buffer */
44240Sstevel@tonic-gate 		size = kobj_file_bufsize;
44250Sstevel@tonic-gate 		buf = kobj_file_buf = kobj_alloc(size, KM_WAIT|KM_TMP);
44260Sstevel@tonic-gate 	}
44270Sstevel@tonic-gate 
44280Sstevel@tonic-gate 	n = snprintf(buf, size, "%s\n", filename);
44290Sstevel@tonic-gate 	if (n > size)
44300Sstevel@tonic-gate 		n = size;
44310Sstevel@tonic-gate 	size -= n;
44320Sstevel@tonic-gate 	buf += n;
44330Sstevel@tonic-gate }
44340Sstevel@tonic-gate #endif	/* __x86 */
44350Sstevel@tonic-gate 
44361544Seschrock static int
44371544Seschrock kobj_boot_fstat(int fd, struct bootstat *stp)
44381544Seschrock {
44391544Seschrock #if defined(__sparc)
44401544Seschrock 	if (!standalone && _ioquiesced)
44411544Seschrock 		return (-1);
44421544Seschrock 	return (BOP_FSTAT(ops, fd, stp));
44431544Seschrock #else
44441544Seschrock 	return (BRD_FSTAT(bfs_ops, fd, stp));
44451544Seschrock #endif
44461544Seschrock }
44471544Seschrock 
44480Sstevel@tonic-gate /*
44490Sstevel@tonic-gate  * XXX these wrappers should go away when sparc is converted
44500Sstevel@tonic-gate  * boot from ramdisk
44510Sstevel@tonic-gate  */
44520Sstevel@tonic-gate static int
44530Sstevel@tonic-gate kobj_boot_open(char *filename, int flags)
44540Sstevel@tonic-gate {
44550Sstevel@tonic-gate #if defined(__sparc)
44560Sstevel@tonic-gate 	/*
44570Sstevel@tonic-gate 	 * If io via bootops is quiesced, it means boot is no longer
44580Sstevel@tonic-gate 	 * available to us.  We make it look as if we can't open the
44590Sstevel@tonic-gate 	 * named file - which is reasonably accurate.
44600Sstevel@tonic-gate 	 */
44610Sstevel@tonic-gate 	if (!standalone && _ioquiesced)
44620Sstevel@tonic-gate 		return (-1);
44630Sstevel@tonic-gate 
44640Sstevel@tonic-gate 	return (BOP_OPEN(ops, filename, flags));
44650Sstevel@tonic-gate #else /* x86 */
44660Sstevel@tonic-gate 	kobj_record_file(filename);
44670Sstevel@tonic-gate 	return (BRD_OPEN(bfs_ops, filename, flags));
44680Sstevel@tonic-gate #endif
44690Sstevel@tonic-gate }
44700Sstevel@tonic-gate 
44710Sstevel@tonic-gate static int
44720Sstevel@tonic-gate kobj_boot_close(int fd)
44730Sstevel@tonic-gate {
44740Sstevel@tonic-gate #if defined(__sparc)
44750Sstevel@tonic-gate 	if (!standalone && _ioquiesced)
44760Sstevel@tonic-gate 		return (-1);
44770Sstevel@tonic-gate 
44780Sstevel@tonic-gate 	return (BOP_CLOSE(ops, fd));
44790Sstevel@tonic-gate #else /* x86 */
44800Sstevel@tonic-gate 	return (BRD_CLOSE(bfs_ops, fd));
44810Sstevel@tonic-gate #endif
44820Sstevel@tonic-gate }
44830Sstevel@tonic-gate 
44840Sstevel@tonic-gate /*ARGSUSED*/
44850Sstevel@tonic-gate static int
44860Sstevel@tonic-gate kobj_boot_seek(int fd, off_t hi, off_t lo)
44870Sstevel@tonic-gate {
44880Sstevel@tonic-gate #if defined(__sparc)
44890Sstevel@tonic-gate 	return (BOP_SEEK(ops, fd, hi, lo));
44900Sstevel@tonic-gate #else
44910Sstevel@tonic-gate 	return (BRD_SEEK(bfs_ops, fd, lo, SEEK_SET));
44920Sstevel@tonic-gate #endif
44930Sstevel@tonic-gate }
44940Sstevel@tonic-gate 
44950Sstevel@tonic-gate static int
44960Sstevel@tonic-gate kobj_boot_read(int fd, caddr_t buf, size_t size)
44970Sstevel@tonic-gate {
44980Sstevel@tonic-gate #if defined(__sparc)
44990Sstevel@tonic-gate 	return (BOP_READ(ops, fd, buf, size));
45000Sstevel@tonic-gate #else
45010Sstevel@tonic-gate 	return (BRD_READ(bfs_ops, fd, buf, size));
45020Sstevel@tonic-gate #endif
45030Sstevel@tonic-gate }
4504