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