17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ea394cb0Sjohansen  * Common Development and Distribution License (the "License").
6ea394cb0Sjohansen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21c9a6ea2eSBryan Cantrill 
227c478bd9Sstevel@tonic-gate /*
23c9a6ea2eSBryan Cantrill  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
243b6e0a59SMatt Amdur  * Copyright (c) 2012 by Delphix. All rights reserved.
254c05824aSMark Brooks  * Copyright 2019 Joyent, Inc.
26*50d4d24eSRobert Mustacchi  * Copyright 2021 Oxide Computer Company
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/param.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <dlfcn.h>
337aec1d6eScindi #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <link.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h>
377c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
387c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
397c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_io.h>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
437c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate int
mdb_module_load(const char * name,int mode)467c478bd9Sstevel@tonic-gate mdb_module_load(const char *name, int mode)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	const char *wformat = "no module '%s' could be found\n";
497c478bd9Sstevel@tonic-gate 	const char *fullname = NULL;
507aec1d6eScindi 	char buf[MAXPATHLEN], *p, *q;
517c478bd9Sstevel@tonic-gate 	int i;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate 	ASSERT(!(mode & MDB_MOD_DEFER));
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate 	if (strchr(name, '/') != NULL) {
567c478bd9Sstevel@tonic-gate 		ASSERT(!(mode & MDB_MOD_BUILTIN));
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 		(void) mdb_iob_snprintf(buf, sizeof (buf), "%s",
597c478bd9Sstevel@tonic-gate 		    strbasename(name));
607aec1d6eScindi 
617aec1d6eScindi 		/*
627aec1d6eScindi 		 * Remove any .so(.[0-9]+)? suffix
637aec1d6eScindi 		 */
644c05824aSMark Brooks 		if ((p = strrchr(buf, '.')) != NULL) {
657aec1d6eScindi 			for (q = p + 1; isdigit(*q); q++)
667aec1d6eScindi 				;
677aec1d6eScindi 
687aec1d6eScindi 			if (*q == '\0') {
694c05824aSMark Brooks 				if (q > p + 1) {
707aec1d6eScindi 
714c05824aSMark Brooks 					/* found digits to remove */
724c05824aSMark Brooks 					*p = '\0';
734c05824aSMark Brooks 				}
744c05824aSMark Brooks 			}
754c05824aSMark Brooks 			if ((p = strrchr(buf, '.')) != NULL) {
764c05824aSMark Brooks 				if (strcmp(p, ".so") == 0) {
774c05824aSMark Brooks 					*p = '\0';
784c05824aSMark Brooks 				}
79ea394cb0Sjohansen 			}
80ea394cb0Sjohansen 		}
817c478bd9Sstevel@tonic-gate 		fullname = name;
827c478bd9Sstevel@tonic-gate 		name = buf;
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	if (!mdb_module_validate_name(name, &wformat))
867c478bd9Sstevel@tonic-gate 		goto err;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (fullname != NULL) {
897c478bd9Sstevel@tonic-gate 		if (access(fullname, F_OK) != 0) {
907c478bd9Sstevel@tonic-gate 			name = fullname; /* for warn() below */
917c478bd9Sstevel@tonic-gate 			goto err;
927c478bd9Sstevel@tonic-gate 		}
937c478bd9Sstevel@tonic-gate 		return (mdb_module_create(name, fullname, mode, NULL));
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/*
977c478bd9Sstevel@tonic-gate 	 * If a simple name is specified, search for it in the module path.
987c478bd9Sstevel@tonic-gate 	 * The module path is searched in order, and for each element we
997c478bd9Sstevel@tonic-gate 	 * look for the following files:
1007c478bd9Sstevel@tonic-gate 	 *
101ea394cb0Sjohansen 	 * 1. If the module name ends in ".so(.[0-9]+)?", search for the literal
1027c478bd9Sstevel@tonic-gate 	 *    name and then search for the name without the [0-9]+ suffix.
1037c478bd9Sstevel@tonic-gate 	 * 2. If the module name ends in ".so", search for the literal name.
1047c478bd9Sstevel@tonic-gate 	 * 3. Search for the module name with ".so" appended.
1057c478bd9Sstevel@tonic-gate 	 *
1067c478bd9Sstevel@tonic-gate 	 * Once a matching file is detected, we attempt to load that module
1077c478bd9Sstevel@tonic-gate 	 * and do not resume our search in the case of an error.
1087c478bd9Sstevel@tonic-gate 	 */
1097c478bd9Sstevel@tonic-gate 	for (i = 0; mdb.m_lpath[i] != NULL; i++) {
1107c478bd9Sstevel@tonic-gate 		if ((p = strrchr(name, '.')) != NULL && *++p != '\0') {
1117c478bd9Sstevel@tonic-gate 			if (strisnum(p) || strcmp(p, "so") == 0) {
1127c478bd9Sstevel@tonic-gate 				(void) mdb_iob_snprintf(buf, sizeof (buf),
1137c478bd9Sstevel@tonic-gate 				    "%s/%s", mdb.m_lpath[i], name);
1147c478bd9Sstevel@tonic-gate 				mdb_dprintf(MDB_DBG_MODULE,
1157c478bd9Sstevel@tonic-gate 				    "checking for %s\n", buf);
1167c478bd9Sstevel@tonic-gate 				if (access(buf, F_OK) == 0) {
1177c478bd9Sstevel@tonic-gate 					return (mdb_module_create(name, buf,
1187c478bd9Sstevel@tonic-gate 					    mode, NULL));
1197c478bd9Sstevel@tonic-gate 				}
1207c478bd9Sstevel@tonic-gate 			}
1217c478bd9Sstevel@tonic-gate 
122ea394cb0Sjohansen 			while (strisnum(p) && (p = strrchr(buf, '.')) != NULL) {
1237c478bd9Sstevel@tonic-gate 				*p = '\0'; /* strip trailing digits */
1247c478bd9Sstevel@tonic-gate 				mdb_dprintf(MDB_DBG_MODULE,
1257c478bd9Sstevel@tonic-gate 				    "checking for %s\n", buf);
1267c478bd9Sstevel@tonic-gate 				if (access(buf, F_OK) == 0) {
1277c478bd9Sstevel@tonic-gate 					return (mdb_module_create(name, buf,
1287c478bd9Sstevel@tonic-gate 					    mode, NULL));
1297c478bd9Sstevel@tonic-gate 				}
1307c478bd9Sstevel@tonic-gate 			}
1317c478bd9Sstevel@tonic-gate 		}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 		(void) mdb_iob_snprintf(buf, sizeof (buf), "%s/%s.so",
1347c478bd9Sstevel@tonic-gate 		    mdb.m_lpath[i], name);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_MODULE, "checking for %s\n", buf);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 		if (access(buf, F_OK) == 0)
1397c478bd9Sstevel@tonic-gate 			return (mdb_module_create(name, buf, mode, NULL));
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate err:
1427c478bd9Sstevel@tonic-gate 	if (!(mode & MDB_MOD_SILENT))
1437c478bd9Sstevel@tonic-gate 		warn(wformat, name);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	return (-1);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate typedef struct mdb_modload_data {
1497c478bd9Sstevel@tonic-gate 	int mld_first;
1507c478bd9Sstevel@tonic-gate 	int mld_mode;
1517c478bd9Sstevel@tonic-gate } mdb_modload_data_t;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1547c478bd9Sstevel@tonic-gate static int
module_load(void * fp,const mdb_map_t * map,const char * fullname)155c9a6ea2eSBryan Cantrill module_load(void *fp, const mdb_map_t *map, const char *fullname)
1567c478bd9Sstevel@tonic-gate {
1577c478bd9Sstevel@tonic-gate 	mdb_modload_data_t *mld = fp;
158c9a6ea2eSBryan Cantrill 	const char *name = strbasename(fullname);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (mdb_module_load(name, mld->mld_mode) == 0 && mdb.m_term != NULL) {
1617c478bd9Sstevel@tonic-gate 		if (mld->mld_first == TRUE) {
1627c478bd9Sstevel@tonic-gate 			mdb_iob_puts(mdb.m_out, "Loading modules: [");
1637c478bd9Sstevel@tonic-gate 			mld->mld_first = FALSE;
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out, " %s", name);
1667c478bd9Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_out);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
169c9a6ea2eSBryan Cantrill 	if (strstr(fullname, "/libc/") != NULL) {
170c9a6ea2eSBryan Cantrill 		/*
171c9a6ea2eSBryan Cantrill 		 * A bit of a kludge:  because we manage alternately capable
172c9a6ea2eSBryan Cantrill 		 * libc instances by mounting the appropriately capable
173c9a6ea2eSBryan Cantrill 		 * instance over /lib/libc.so.1, we may find that our object
174c9a6ea2eSBryan Cantrill 		 * list does not contain libc.so.1, but rather one of its
175c9a6ea2eSBryan Cantrill 		 * hwcap variants.  Unfortunately, there is not a way of
176c9a6ea2eSBryan Cantrill 		 * getting from this shared object to the object that it is
177c9a6ea2eSBryan Cantrill 		 * effectively interposing on -- which means that without
178c9a6ea2eSBryan Cantrill 		 * special processing, we will not load any libc.so dmod.  So
179c9a6ea2eSBryan Cantrill 		 * if we see that we have a shared object coming out of the
180c9a6ea2eSBryan Cantrill 		 * "libc" directory, we assume that we have a "libc-like"
181c9a6ea2eSBryan Cantrill 		 * object, and explicitly load the "libc.so" dmod.
182c9a6ea2eSBryan Cantrill 		 */
183c9a6ea2eSBryan Cantrill 		return (module_load(fp, map, "libc.so.1"));
184c9a6ea2eSBryan Cantrill 	}
185c9a6ea2eSBryan Cantrill 
186*50d4d24eSRobert Mustacchi 	if (strstr(fullname, "ld.so") != NULL) {
187*50d4d24eSRobert Mustacchi 		/*
188*50d4d24eSRobert Mustacchi 		 * This is even more of a kludge. But if we find something has
189*50d4d24eSRobert Mustacchi 		 * basically tried to load ld, we will always implicitly load
190*50d4d24eSRobert Mustacchi 		 * the list dmod because several binaries and libraries just
191*50d4d24eSRobert Mustacchi 		 * build it as a .o and include it in their ELF object.
192*50d4d24eSRobert Mustacchi 		 */
193*50d4d24eSRobert Mustacchi 		(void) mdb_module_load("list", mld->mld_mode);
194*50d4d24eSRobert Mustacchi 	}
195*50d4d24eSRobert Mustacchi 
1967c478bd9Sstevel@tonic-gate 	return (0);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate void
mdb_module_load_all(int mode)2007c478bd9Sstevel@tonic-gate mdb_module_load_all(int mode)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	uint_t oflag = mdb_iob_getflags(mdb.m_out) & MDB_IOB_PGENABLE;
2037c478bd9Sstevel@tonic-gate 	mdb_modload_data_t mld;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	mld.mld_first = TRUE;
2067c478bd9Sstevel@tonic-gate 	mld.mld_mode = mode | MDB_MOD_LOCAL | MDB_MOD_SILENT;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	mdb_iob_clrflags(mdb.m_out, oflag);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_object_iter(mdb.m_target, module_load, &mld);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (mdb.m_term != NULL && mld.mld_first == FALSE)
2137c478bd9Sstevel@tonic-gate 		mdb_iob_puts(mdb.m_out, " ]\n");
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	mdb_iob_setflags(mdb.m_out, oflag);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2183b6e0a59SMatt Amdur /*ARGSUSED*/
2197c478bd9Sstevel@tonic-gate int
mdb_module_unload(const char * name,int mode)2207c478bd9Sstevel@tonic-gate mdb_module_unload(const char *name, int mode)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate 	ASSERT((mode & ~MDB_MOD_SILENT) == 0);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	return (mdb_module_unload_common(name));
2257c478bd9Sstevel@tonic-gate }
226