xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_kvm.c (revision 9c3024a3)
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
5ae115bc7Smrj  * Common Development and Distribution License (the "License").
6ae115bc7Smrj  * 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  */
217c478bd9Sstevel@tonic-gate /*
22f6e214c7SGavin Maltby  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
251320caf7SBryan Cantrill /*
268eb8717cSJohn Levon  * Copyright 2019 Joyent, Inc.
271320caf7SBryan Cantrill  */
281320caf7SBryan Cantrill 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Libkvm Kernel Target
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * The libkvm kernel target provides access to both crash dumps and live
337c478bd9Sstevel@tonic-gate  * kernels through /dev/ksyms and /dev/kmem, using the facilities provided by
347c478bd9Sstevel@tonic-gate  * the libkvm.so library.  The target-specific data structures are shared
357c478bd9Sstevel@tonic-gate  * between this file (common code) and the ISA-dependent parts of the target,
367c478bd9Sstevel@tonic-gate  * and so they are defined in the mdb_kvm.h header.  The target processes an
377c478bd9Sstevel@tonic-gate  * "executable" (/dev/ksyms or the unix.X file) which contains a primary
387c478bd9Sstevel@tonic-gate  * .symtab and .dynsym, and then also iterates over the krtld module chain in
397c478bd9Sstevel@tonic-gate  * the kernel in order to obtain a list of loaded modules and per-module symbol
407c478bd9Sstevel@tonic-gate  * tables.  To improve startup performance, the per-module symbol tables are
417c478bd9Sstevel@tonic-gate  * instantiated on-the-fly whenever an address lookup falls within the text
427c478bd9Sstevel@tonic-gate  * section of a given module.  The target also relies on services from the
437c478bd9Sstevel@tonic-gate  * mdb_ks (kernel support) module, which contains pieces of the implementation
447c478bd9Sstevel@tonic-gate  * that must be compiled against the kernel implementation.
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
487c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
497c478bd9Sstevel@tonic-gate #include <sys/kobj_impl.h>
507c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
517c478bd9Sstevel@tonic-gate #include <sys/panic.h>
527c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h>
537c478bd9Sstevel@tonic-gate #include <sys/dumpadm.h>
548eb8717cSJohn Levon #include <sys/uuid.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <dlfcn.h>
577c478bd9Sstevel@tonic-gate #include <libctf.h>
587c478bd9Sstevel@tonic-gate #include <string.h>
597c478bd9Sstevel@tonic-gate #include <fcntl.h>
607c478bd9Sstevel@tonic-gate #include <errno.h>
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
637c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
647c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
657c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
667c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
677c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
687c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
697c478bd9Sstevel@tonic-gate #include <mdb/mdb_kvm.h>
707c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h>
71843e1988Sjohnlev #include <mdb/mdb_kb.h>
728eb8717cSJohn Levon #include <mdb/mdb_ks.h>
737c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #define	KT_RELOC_BUF(buf, obase, nbase) \
767c478bd9Sstevel@tonic-gate 	((uintptr_t)(buf) - (uintptr_t)(obase) + (uintptr_t)(nbase))
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	KT_BAD_BUF(buf, base, size) \
797c478bd9Sstevel@tonic-gate 	((uintptr_t)(buf) < (uintptr_t)(base) || \
807c478bd9Sstevel@tonic-gate 	((uintptr_t)(buf) >= (uintptr_t)(base) + (uintptr_t)(size)))
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate typedef struct kt_symarg {
837c478bd9Sstevel@tonic-gate 	mdb_tgt_sym_f *sym_cb;		/* Caller's callback function */
847c478bd9Sstevel@tonic-gate 	void *sym_data;			/* Callback function argument */
857c478bd9Sstevel@tonic-gate 	uint_t sym_type;		/* Symbol type/binding filter */
867c478bd9Sstevel@tonic-gate 	mdb_syminfo_t sym_info;		/* Symbol id and table id */
877c478bd9Sstevel@tonic-gate 	const char *sym_obj;		/* Containing object */
887c478bd9Sstevel@tonic-gate } kt_symarg_t;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate typedef struct kt_maparg {
917c478bd9Sstevel@tonic-gate 	mdb_tgt_t *map_target;		/* Target used for mapping iter */
927c478bd9Sstevel@tonic-gate 	mdb_tgt_map_f *map_cb;		/* Caller's callback function */
937c478bd9Sstevel@tonic-gate 	void *map_data;			/* Callback function argument */
947c478bd9Sstevel@tonic-gate } kt_maparg_t;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static const char KT_MODULE[] = "mdb_ks";
977c478bd9Sstevel@tonic-gate static const char KT_CTFPARENT[] = "genunix";
987c478bd9Sstevel@tonic-gate 
998eb8717cSJohn Levon static void (*print_buildversion)(void);
1008eb8717cSJohn Levon 
1017c478bd9Sstevel@tonic-gate static void
kt_load_module(kt_data_t * kt,mdb_tgt_t * t,kt_module_t * km)1027c478bd9Sstevel@tonic-gate kt_load_module(kt_data_t *kt, mdb_tgt_t *t, kt_module_t *km)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	km->km_data = mdb_alloc(km->km_datasz, UM_SLEEP);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_vread(t, km->km_data, km->km_datasz, km->km_symspace_va);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	km->km_symbuf = (void *)
1097c478bd9Sstevel@tonic-gate 	    KT_RELOC_BUF(km->km_symtab_va, km->km_symspace_va, km->km_data);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	km->km_strtab = (char *)
1127c478bd9Sstevel@tonic-gate 	    KT_RELOC_BUF(km->km_strtab_va, km->km_symspace_va, km->km_data);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	km->km_symtab = mdb_gelf_symtab_create_raw(&kt->k_file->gf_ehdr,
1157c478bd9Sstevel@tonic-gate 	    &km->km_symtab_hdr, km->km_symbuf,
1167c478bd9Sstevel@tonic-gate 	    &km->km_strtab_hdr, km->km_strtab, MDB_TGT_SYMTAB);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static void
kt_load_modules(kt_data_t * kt,mdb_tgt_t * t)1207c478bd9Sstevel@tonic-gate kt_load_modules(kt_data_t *kt, mdb_tgt_t *t)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
1237c478bd9Sstevel@tonic-gate 	uintptr_t addr, head;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	struct module kmod;
1267c478bd9Sstevel@tonic-gate 	struct modctl ctl;
1277c478bd9Sstevel@tonic-gate 	Shdr symhdr, strhdr;
1287c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	kt_module_t *km;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	if (mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
1337c478bd9Sstevel@tonic-gate 	    "modules", &sym, NULL) == -1) {
1347c478bd9Sstevel@tonic-gate 		warn("failed to get 'modules' symbol");
1357c478bd9Sstevel@tonic-gate 		return;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &ctl, sizeof (ctl),
1397c478bd9Sstevel@tonic-gate 	    MDB_TGT_OBJ_EXEC, "modules") != sizeof (ctl)) {
1407c478bd9Sstevel@tonic-gate 		warn("failed to read 'modules' struct");
1417c478bd9Sstevel@tonic-gate 		return;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	addr = head = (uintptr_t)sym.st_value;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	do {
147892ad162SToomas Soome 		if (addr == 0)
1487c478bd9Sstevel@tonic-gate 			break; /* Avoid spurious NULL pointers in list */
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(t, &ctl, sizeof (ctl), addr) == -1) {
1517c478bd9Sstevel@tonic-gate 			warn("failed to read modctl at %p", (void *)addr);
1527c478bd9Sstevel@tonic-gate 			return;
1537c478bd9Sstevel@tonic-gate 		}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 		if (ctl.mod_mp == NULL)
1567c478bd9Sstevel@tonic-gate 			continue; /* No associated krtld structure */
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, name, MAXNAMELEN,
1597c478bd9Sstevel@tonic-gate 		    (uintptr_t)ctl.mod_modname) <= 0) {
1607c478bd9Sstevel@tonic-gate 			warn("failed to read module name at %p",
1617c478bd9Sstevel@tonic-gate 			    (void *)ctl.mod_modname);
1627c478bd9Sstevel@tonic-gate 			continue;
1637c478bd9Sstevel@tonic-gate 		}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_KMOD, "reading mod %s (%p)\n",
1667c478bd9Sstevel@tonic-gate 		    name, (void *)addr);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 		if (mdb_nv_lookup(&kt->k_modules, name) != NULL) {
1697c478bd9Sstevel@tonic-gate 			warn("skipping duplicate module '%s', id=%d\n",
1707c478bd9Sstevel@tonic-gate 			    name, ctl.mod_id);
1717c478bd9Sstevel@tonic-gate 			continue;
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(t, &kmod, sizeof (kmod),
1757c478bd9Sstevel@tonic-gate 		    (uintptr_t)ctl.mod_mp) == -1) {
1767c478bd9Sstevel@tonic-gate 			warn("failed to read module at %p\n",
1777c478bd9Sstevel@tonic-gate 			    (void *)ctl.mod_mp);
1787c478bd9Sstevel@tonic-gate 			continue;
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		if (kmod.symspace == NULL || kmod.symhdr == NULL ||
1827c478bd9Sstevel@tonic-gate 		    kmod.strhdr == NULL) {
1837c478bd9Sstevel@tonic-gate 			/*
1847c478bd9Sstevel@tonic-gate 			 * If no buffer for the symbols has been allocated,
1857c478bd9Sstevel@tonic-gate 			 * or the shdrs for .symtab and .strtab are missing,
1867c478bd9Sstevel@tonic-gate 			 * then we're out of luck.
1877c478bd9Sstevel@tonic-gate 			 */
1887c478bd9Sstevel@tonic-gate 			continue;
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(t, &symhdr, sizeof (Shdr),
1927c478bd9Sstevel@tonic-gate 		    (uintptr_t)kmod.symhdr) == -1) {
1937c478bd9Sstevel@tonic-gate 			warn("failed to read .symtab header for '%s', id=%d",
1947c478bd9Sstevel@tonic-gate 			    name, ctl.mod_id);
1957c478bd9Sstevel@tonic-gate 			continue;
1967c478bd9Sstevel@tonic-gate 		}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(t, &strhdr, sizeof (Shdr),
1997c478bd9Sstevel@tonic-gate 		    (uintptr_t)kmod.strhdr) == -1) {
2007c478bd9Sstevel@tonic-gate 			warn("failed to read .strtab header for '%s', id=%d",
2017c478bd9Sstevel@tonic-gate 			    name, ctl.mod_id);
2027c478bd9Sstevel@tonic-gate 			continue;
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		/*
2067c478bd9Sstevel@tonic-gate 		 * Now get clever: f(*^ing krtld didn't used to bother updating
2077c478bd9Sstevel@tonic-gate 		 * its own kmod.symsize value.  We know that prior to this bug
2087c478bd9Sstevel@tonic-gate 		 * being fixed, symspace was a contiguous buffer containing
2097c478bd9Sstevel@tonic-gate 		 * .symtab, .strtab, and the symbol hash table in that order.
2107c478bd9Sstevel@tonic-gate 		 * So if symsize is zero, recompute it as the size of .symtab
2117c478bd9Sstevel@tonic-gate 		 * plus the size of .strtab.  We don't need to load the hash
2127c478bd9Sstevel@tonic-gate 		 * table anyway since we re-hash all the symbols internally.
2137c478bd9Sstevel@tonic-gate 		 */
2147c478bd9Sstevel@tonic-gate 		if (kmod.symsize == 0)
2157c478bd9Sstevel@tonic-gate 			kmod.symsize = symhdr.sh_size + strhdr.sh_size;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 		/*
2187c478bd9Sstevel@tonic-gate 		 * Similar logic can be used to make educated guesses
2197c478bd9Sstevel@tonic-gate 		 * at the values of kmod.symtbl and kmod.strings.
2207c478bd9Sstevel@tonic-gate 		 */
2217c478bd9Sstevel@tonic-gate 		if (kmod.symtbl == NULL)
2227c478bd9Sstevel@tonic-gate 			kmod.symtbl = kmod.symspace;
2237c478bd9Sstevel@tonic-gate 		if (kmod.strings == NULL)
2247c478bd9Sstevel@tonic-gate 			kmod.strings = kmod.symspace + symhdr.sh_size;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		/*
2277c478bd9Sstevel@tonic-gate 		 * Make sure things seem reasonable before we proceed
2287c478bd9Sstevel@tonic-gate 		 * to actually read and decipher the symspace.
2297c478bd9Sstevel@tonic-gate 		 */
2307c478bd9Sstevel@tonic-gate 		if (KT_BAD_BUF(kmod.symtbl, kmod.symspace, kmod.symsize) ||
2317c478bd9Sstevel@tonic-gate 		    KT_BAD_BUF(kmod.strings, kmod.symspace, kmod.symsize)) {
2327c478bd9Sstevel@tonic-gate 			warn("skipping module '%s', id=%d (corrupt symspace)\n",
2337c478bd9Sstevel@tonic-gate 			    name, ctl.mod_id);
2347c478bd9Sstevel@tonic-gate 			continue;
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 		km = mdb_zalloc(sizeof (kt_module_t), UM_SLEEP);
2387c478bd9Sstevel@tonic-gate 		km->km_name = strdup(name);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&kt->k_modules, km->km_name, NULL,
2417c478bd9Sstevel@tonic-gate 		    (uintptr_t)km, MDB_NV_EXTNAME);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 		km->km_datasz = kmod.symsize;
2447c478bd9Sstevel@tonic-gate 		km->km_symspace_va = (uintptr_t)kmod.symspace;
2457c478bd9Sstevel@tonic-gate 		km->km_symtab_va = (uintptr_t)kmod.symtbl;
2467c478bd9Sstevel@tonic-gate 		km->km_strtab_va = (uintptr_t)kmod.strings;
2477c478bd9Sstevel@tonic-gate 		km->km_symtab_hdr = symhdr;
2487c478bd9Sstevel@tonic-gate 		km->km_strtab_hdr = strhdr;
2497c478bd9Sstevel@tonic-gate 		km->km_text_va = (uintptr_t)kmod.text;
2507c478bd9Sstevel@tonic-gate 		km->km_text_size = kmod.text_size;
2517c478bd9Sstevel@tonic-gate 		km->km_data_va = (uintptr_t)kmod.data;
2527c478bd9Sstevel@tonic-gate 		km->km_data_size = kmod.data_size;
2537c478bd9Sstevel@tonic-gate 		km->km_bss_va = (uintptr_t)kmod.bss;
2547c478bd9Sstevel@tonic-gate 		km->km_bss_size = kmod.bss_size;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		if (kt->k_ctfvalid) {
2577c478bd9Sstevel@tonic-gate 			km->km_ctf_va = (uintptr_t)kmod.ctfdata;
2587c478bd9Sstevel@tonic-gate 			km->km_ctf_size = kmod.ctfsize;
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 		/*
2627c478bd9Sstevel@tonic-gate 		 * Add the module to the end of the list of modules in load-
2637c478bd9Sstevel@tonic-gate 		 * dependency order.  This is needed to load the corresponding
2647c478bd9Sstevel@tonic-gate 		 * debugger modules in the same order for layering purposes.
2657c478bd9Sstevel@tonic-gate 		 */
2667c478bd9Sstevel@tonic-gate 		mdb_list_append(&kt->k_modlist, km);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		if (t->t_flags & MDB_TGT_F_PRELOAD) {
2697c478bd9Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_out, " %s", name);
2707c478bd9Sstevel@tonic-gate 			mdb_iob_flush(mdb.m_out);
2717c478bd9Sstevel@tonic-gate 			kt_load_module(kt, t, km);
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	} while ((addr = (uintptr_t)ctl.mod_next) != head);
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate int
kt_setflags(mdb_tgt_t * t,int flags)2787c478bd9Sstevel@tonic-gate kt_setflags(mdb_tgt_t *t, int flags)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	int iochg = ((flags ^ t->t_flags) & MDB_TGT_F_ALLOWIO) &&
2817c478bd9Sstevel@tonic-gate 	    !mdb_prop_postmortem;
2827c478bd9Sstevel@tonic-gate 	int rwchg = (flags ^ t->t_flags) & MDB_TGT_F_RDWR;
2837c478bd9Sstevel@tonic-gate 	kt_data_t *kt = t->t_data;
2847c478bd9Sstevel@tonic-gate 	const char *kvmfile;
285843e1988Sjohnlev 	void *cookie;
2867c478bd9Sstevel@tonic-gate 	int mode;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	if (!iochg && !rwchg)
2897c478bd9Sstevel@tonic-gate 		return (0);
2907c478bd9Sstevel@tonic-gate 
291843e1988Sjohnlev 	if (kt->k_xpv_domu) {
292843e1988Sjohnlev 		warn("read-only target");
293843e1988Sjohnlev 		return (-1);
294843e1988Sjohnlev 	}
295843e1988Sjohnlev 
2967c478bd9Sstevel@tonic-gate 	if (iochg) {
2977c478bd9Sstevel@tonic-gate 		kvmfile = (flags & MDB_TGT_F_ALLOWIO) ? "/dev/allkmem" :
2987c478bd9Sstevel@tonic-gate 		    "/dev/kmem";
2997c478bd9Sstevel@tonic-gate 	} else {
3007c478bd9Sstevel@tonic-gate 		kvmfile = kt->k_kvmfile;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY;
3047c478bd9Sstevel@tonic-gate 
305843e1988Sjohnlev 	if ((cookie = kt->k_kb_ops->kb_open(kt->k_symfile, kvmfile, NULL, mode,
3067c478bd9Sstevel@tonic-gate 	    mdb.m_pname)) == NULL) {
3077c478bd9Sstevel@tonic-gate 		/* We failed to re-open, so don't change t_flags */
3087c478bd9Sstevel@tonic-gate 		warn("failed to re-open target");
3097c478bd9Sstevel@tonic-gate 		return (-1);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/*
3137c478bd9Sstevel@tonic-gate 	 * We successfully reopened the target, so update k_kvmfile.  Also set
3147c478bd9Sstevel@tonic-gate 	 * the RDWR and ALLOWIO bits in t_flags to match those in flags.
3157c478bd9Sstevel@tonic-gate 	 */
316843e1988Sjohnlev 	(void) kt->k_kb_ops->kb_close(kt->k_cookie);
3177c478bd9Sstevel@tonic-gate 	kt->k_cookie = cookie;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if (kvmfile != kt->k_kvmfile) {
3207c478bd9Sstevel@tonic-gate 		strfree(kt->k_kvmfile);
3217c478bd9Sstevel@tonic-gate 		kt->k_kvmfile = strdup(kvmfile);
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	t->t_flags = (t->t_flags & ~(MDB_TGT_F_RDWR | MDB_TGT_F_ALLOWIO)) |
3257c478bd9Sstevel@tonic-gate 	    (flags & (MDB_TGT_F_RDWR | MDB_TGT_F_ALLOWIO));
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	return (0);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Determine which PIDs (if any) have their pages saved in the dump.  We
3327c478bd9Sstevel@tonic-gate  * do this by looking for content flags in dump_flags in the header.  These
3337c478bd9Sstevel@tonic-gate  * flags, which won't be set in older dumps, tell us whether a single process
3347c478bd9Sstevel@tonic-gate  * has had its pages included in the dump.  If a single process has been
3357c478bd9Sstevel@tonic-gate  * included, we need to get the PID for that process from the dump_pids
3367c478bd9Sstevel@tonic-gate  * array in the dump.
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate static int
kt_find_dump_contents(kt_data_t * kt)3397c478bd9Sstevel@tonic-gate kt_find_dump_contents(kt_data_t *kt)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	dumphdr_t *dh = kt->k_dumphdr;
3427c478bd9Sstevel@tonic-gate 	pid_t pid = -1;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if (dh->dump_flags & DF_ALL)
3457c478bd9Sstevel@tonic-gate 		return (KT_DUMPCONTENT_ALL);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (dh->dump_flags & DF_CURPROC) {
3487c478bd9Sstevel@tonic-gate 		if ((pid = kt->k_dump_find_curproc()) == -1)
3497c478bd9Sstevel@tonic-gate 			return (KT_DUMPCONTENT_INVALID);
3507c478bd9Sstevel@tonic-gate 		else
3517c478bd9Sstevel@tonic-gate 			return (pid);
3527c478bd9Sstevel@tonic-gate 	} else {
3537c478bd9Sstevel@tonic-gate 		return (KT_DUMPCONTENT_KERNEL);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate static int
kt_dump_contains_proc(mdb_tgt_t * t,void * context)3587c478bd9Sstevel@tonic-gate kt_dump_contains_proc(mdb_tgt_t *t, void *context)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	kt_data_t *kt = t->t_data;
3617c478bd9Sstevel@tonic-gate 	pid_t (*f_pid)(uintptr_t);
3627c478bd9Sstevel@tonic-gate 	pid_t reqpid;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	switch (kt->k_dumpcontent) {
3657c478bd9Sstevel@tonic-gate 	case KT_DUMPCONTENT_KERNEL:
3667c478bd9Sstevel@tonic-gate 		return (0);
3677c478bd9Sstevel@tonic-gate 	case KT_DUMPCONTENT_ALL:
3687c478bd9Sstevel@tonic-gate 		return (1);
3697c478bd9Sstevel@tonic-gate 	case KT_DUMPCONTENT_INVALID:
3707c478bd9Sstevel@tonic-gate 		goto procnotfound;
3717c478bd9Sstevel@tonic-gate 	default:
3727c478bd9Sstevel@tonic-gate 		f_pid = (pid_t (*)()) dlsym(RTLD_NEXT, "mdb_kproc_pid");
3737c478bd9Sstevel@tonic-gate 		if (f_pid == NULL)
3747c478bd9Sstevel@tonic-gate 			goto procnotfound;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		reqpid = f_pid((uintptr_t)context);
3777c478bd9Sstevel@tonic-gate 		if (reqpid == -1)
3787c478bd9Sstevel@tonic-gate 			goto procnotfound;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		return (kt->k_dumpcontent == reqpid);
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate procnotfound:
3847c478bd9Sstevel@tonic-gate 	warn("unable to determine whether dump contains proc %p\n", context);
3857c478bd9Sstevel@tonic-gate 	return (1);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate int
kt_setcontext(mdb_tgt_t * t,void * context)3897c478bd9Sstevel@tonic-gate kt_setcontext(mdb_tgt_t *t, void *context)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	if (context != NULL) {
3927c478bd9Sstevel@tonic-gate 		const char *argv[2];
3937c478bd9Sstevel@tonic-gate 		int argc = 0;
3947c478bd9Sstevel@tonic-gate 		mdb_tgt_t *ct;
3957c478bd9Sstevel@tonic-gate 		kt_data_t *kt = t->t_data;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		argv[argc++] = (const char *)context;
3987c478bd9Sstevel@tonic-gate 		argv[argc] = NULL;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		if (kt->k_dumphdr != NULL &&
4017c478bd9Sstevel@tonic-gate 		    !kt_dump_contains_proc(t, context)) {
4027c478bd9Sstevel@tonic-gate 			warn("dump does not contain pages for proc %p\n",
4037c478bd9Sstevel@tonic-gate 			    context);
4047c478bd9Sstevel@tonic-gate 			return (-1);
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		if ((ct = mdb_tgt_create(mdb_kproc_tgt_create,
4087c478bd9Sstevel@tonic-gate 		    t->t_flags, argc, argv)) == NULL)
4097c478bd9Sstevel@tonic-gate 			return (-1);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 		mdb_printf("debugger context set to proc %p\n", context);
4127c478bd9Sstevel@tonic-gate 		mdb_tgt_activate(ct);
4137c478bd9Sstevel@tonic-gate 	} else
4147c478bd9Sstevel@tonic-gate 		mdb_printf("debugger context set to kernel\n");
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	return (0);
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate static int
kt_stack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4207c478bd9Sstevel@tonic-gate kt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 	kt_data_t *kt = mdb.m_target->t_data;
4237c478bd9Sstevel@tonic-gate 	return (kt->k_dcmd_stack(addr, flags, argc, argv));
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate static int
kt_stackv(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4277c478bd9Sstevel@tonic-gate kt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	kt_data_t *kt = mdb.m_target->t_data;
4307c478bd9Sstevel@tonic-gate 	return (kt->k_dcmd_stackv(addr, flags, argc, argv));
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate static int
kt_stackr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4347c478bd9Sstevel@tonic-gate kt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	kt_data_t *kt = mdb.m_target->t_data;
4377c478bd9Sstevel@tonic-gate 	return (kt->k_dcmd_stackr(addr, flags, argc, argv));
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate static int
kt_regs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4417c478bd9Sstevel@tonic-gate kt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4427c478bd9Sstevel@tonic-gate {
4437c478bd9Sstevel@tonic-gate 	kt_data_t *kt = mdb.m_target->t_data;
444843e1988Sjohnlev 
445843e1988Sjohnlev 	if (argc != 0 || (flags & DCMD_ADDRSPEC))
446843e1988Sjohnlev 		return (DCMD_USAGE);
447843e1988Sjohnlev 
448843e1988Sjohnlev 	addr = (uintptr_t)kt->k_regs;
449843e1988Sjohnlev 
4507c478bd9Sstevel@tonic-gate 	return (kt->k_dcmd_regs(addr, flags, argc, argv));
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
453843e1988Sjohnlev #ifdef __x86
454843e1988Sjohnlev static int
kt_cpustack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)455843e1988Sjohnlev kt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
456843e1988Sjohnlev {
457843e1988Sjohnlev 	kt_data_t *kt = mdb.m_target->t_data;
458843e1988Sjohnlev 	return (kt->k_dcmd_cpustack(addr, flags, argc, argv));
459843e1988Sjohnlev }
460843e1988Sjohnlev 
461843e1988Sjohnlev static int
kt_cpuregs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)462843e1988Sjohnlev kt_cpuregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
463843e1988Sjohnlev {
464843e1988Sjohnlev 	kt_data_t *kt = mdb.m_target->t_data;
465843e1988Sjohnlev 	return (kt->k_dcmd_cpuregs(addr, flags, argc, argv));
466843e1988Sjohnlev }
467843e1988Sjohnlev #endif /* __x86 */
468843e1988Sjohnlev 
4697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4707c478bd9Sstevel@tonic-gate static int
kt_status_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4717c478bd9Sstevel@tonic-gate kt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	kt_data_t *kt = mdb.m_target->t_data;
4747c478bd9Sstevel@tonic-gate 	struct utsname uts;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	bzero(&uts, sizeof (uts));
4777c478bd9Sstevel@tonic-gate 	(void) strcpy(uts.nodename, "unknown machine");
4787c478bd9Sstevel@tonic-gate 	(void) kt_uname(mdb.m_target, &uts);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	if (mdb_prop_postmortem) {
481843e1988Sjohnlev 		mdb_printf("debugging %scrash dump %s (%d-bit) from %s\n",
482843e1988Sjohnlev 		    kt->k_xpv_domu ? "domain " : "", kt->k_kvmfile,
483843e1988Sjohnlev 		    (int)(sizeof (void *) * NBBY), uts.nodename);
4847c478bd9Sstevel@tonic-gate 	} else {
4857c478bd9Sstevel@tonic-gate 		mdb_printf("debugging live kernel (%d-bit) on %s\n",
4867c478bd9Sstevel@tonic-gate 		    (int)(sizeof (void *) * NBBY), uts.nodename);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	mdb_printf("operating system: %s %s (%s)\n",
4907c478bd9Sstevel@tonic-gate 	    uts.release, uts.version, uts.machine);
4917c478bd9Sstevel@tonic-gate 
4928eb8717cSJohn Levon 	if (print_buildversion != NULL)
4938eb8717cSJohn Levon 		print_buildversion();
4948eb8717cSJohn Levon 
4957c478bd9Sstevel@tonic-gate 	if (kt->k_dumphdr) {
4967c478bd9Sstevel@tonic-gate 		dumphdr_t *dh = kt->k_dumphdr;
4977c478bd9Sstevel@tonic-gate 
498f6e214c7SGavin Maltby 		mdb_printf("image uuid: %s\n", dh->dump_uuid[0] != '\0' ?
499f6e214c7SGavin Maltby 		    dh->dump_uuid : "(not set)");
5007c478bd9Sstevel@tonic-gate 		mdb_printf("panic message: %s\n", dh->dump_panicstring);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		kt->k_dump_print_content(dh, kt->k_dumpcontent);
503f6e214c7SGavin Maltby 	} else {
5048eb8717cSJohn Levon 		char uuid[UUID_PRINTABLE_STRING_LENGTH];
505f6e214c7SGavin Maltby 
5068eb8717cSJohn Levon 		if (mdb_readsym(uuid, sizeof (uuid),
5078eb8717cSJohn Levon 		    "dump_osimage_uuid") == sizeof (uuid) &&
5088eb8717cSJohn Levon 		    uuid[sizeof (uuid) - 1] == '\0') {
5098eb8717cSJohn Levon 			mdb_printf("image uuid: %s\n", uuid[0] != '\0' ?
5108eb8717cSJohn Levon 			    uuid : "(not set)");
511f6e214c7SGavin Maltby 		}
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate static const mdb_dcmd_t kt_dcmds[] = {
5187c478bd9Sstevel@tonic-gate 	{ "$c", "?[cnt]", "print stack backtrace", kt_stack },
5197c478bd9Sstevel@tonic-gate 	{ "$C", "?[cnt]", "print stack backtrace", kt_stackv },
5207c478bd9Sstevel@tonic-gate 	{ "$r", NULL, "print general-purpose registers", kt_regs },
5217c478bd9Sstevel@tonic-gate 	{ "$?", NULL, "print status and registers", kt_regs },
5227c478bd9Sstevel@tonic-gate 	{ "regs", NULL, "print general-purpose registers", kt_regs },
5237c478bd9Sstevel@tonic-gate 	{ "stack", "?[cnt]", "print stack backtrace", kt_stack },
5247c478bd9Sstevel@tonic-gate 	{ "stackregs", "?", "print stack backtrace and registers", kt_stackr },
525843e1988Sjohnlev #ifdef __x86
526843e1988Sjohnlev 	{ "cpustack", "?[-v] [-c cpuid] [cnt]", "print stack backtrace for a "
527843e1988Sjohnlev 	    "specific CPU", kt_cpustack },
528843e1988Sjohnlev 	{ "cpuregs", "?[-c cpuid]", "print general-purpose registers for a "
529843e1988Sjohnlev 	    "specific CPU", kt_cpuregs },
530843e1988Sjohnlev #endif
5317c478bd9Sstevel@tonic-gate 	{ "status", NULL, "print summary of current target", kt_status_dcmd },
5327c478bd9Sstevel@tonic-gate 	{ NULL }
5337c478bd9Sstevel@tonic-gate };
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate static uintmax_t
reg_disc_get(const mdb_var_t * v)5367c478bd9Sstevel@tonic-gate reg_disc_get(const mdb_var_t *v)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = MDB_NV_COOKIE(v);
5397c478bd9Sstevel@tonic-gate 	kt_data_t *kt = t->t_data;
5407c478bd9Sstevel@tonic-gate 	mdb_tgt_reg_t r = 0;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_getareg(t, kt->k_tid, mdb_nv_get_name(v), &r);
5437c478bd9Sstevel@tonic-gate 	return (r);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
546ae115bc7Smrj static kt_module_t *
kt_module_by_name(kt_data_t * kt,const char * name)547ae115bc7Smrj kt_module_by_name(kt_data_t *kt, const char *name)
548ae115bc7Smrj {
549ae115bc7Smrj 	kt_module_t *km;
550